home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tex
/
macros
/
source
/
contrib
/
supported
/
xypic
/
src
/
xy.doc
< prev
next >
Wrap
Text File
|
1995-03-15
|
223KB
|
6,531 lines
%% $Id: xy.doc,v 2.12 1994/10/25 11:55:12 kris Exp $
%%
%% Basic XY-pictures: XY-pic bootstrap and kernel macros.
%% Copyright (c) 1991-1994 Kristoffer H. Rose <kris@diku.dk>
%%
%% This file is part of the XY-pic package for graphs and diagrams in TeX.
%% Copyright (c) 1991-1994 Kristoffer H. Rose <kris@diku.dk>
%%
%% The XY-pic package is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published by the
%% Free Software Foundation; either version 2 of the License, or (at your
%% option) any later version.
%%
%% The XY-pic package is distributed in the hope that it will be useful, but
%% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
%% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
%% for more details.
%%
%% You should have received a copy of the GNU General Public License along
%% with this package; if not, write to the Free Software Foundation, Inc.,
%% 675 Mass Ave, Cambridge, MA 02139, USA.
%%
\ifx\xyloaded\undefined\else \message{not reloaded}\endinput \fi
\let\xyloaded=\relax
% NOTE: Apart from the actual macros (as also found in xy.tex), this file
% contains both the XY-pic kernel reference manual and TeXnical documentation.
% See xyrefer.man and xysource.man for how to typeset this information.
\message{Bootstrap\string'ing\string:}
{\catcode96 12\catcode`\#6\catcode`\.12\catcode`\:12\catcode`\'12\catcode`\@11
\ifx\xywarnifdefined\undefined\else \immediate\write16{}%
\immediate\write16{%
XY-pic Warning: \string\xywarnifdefined\space redefined.}%
\immediate\write16{}\fi
\gdef\xywarnifdefined#1{\ifx#1\undefined\else \immediate\write16{}%
\immediate\write16{%
XY-pic Warning: `\string#1' redefined.}\immediate\write16{}\fi}
\xywarnifdefined\xydef@ \gdef\xydef@#1{\xywarnifdefined#1\def#1}
\xywarnifdefined\xylet@ \gdef\xylet@#1{\xywarnifdefined#1\let#1}
\xywarnifdefined\xynew@
\gdef\xynew@#1#2{\xywarnifdefined#2\csname new#1\endcsname#2}}
\message{catcodes\string,}
\xywarnifdefined\xyuncatcodes \edef\xyuncatcodes{%
\catcode92 0 \catcode123 1 \catcode125 2 \catcode37 14
\catcode 9 \the\catcode 9 \catcode10 \the\catcode10 \catcode12 \the\catcode12
\catcode35 \the\catcode35 \catcode36 \the\catcode36 \catcode38 \the\catcode38
\catcode43 \the\catcode43 \catcode45 \the\catcode45 \catcode46 \the\catcode46
\catcode47 \the\catcode47
\catcode60 \the\catcode60 \catcode61 \the\catcode61 \catcode62 \the\catcode62
\catcode64 \the\catcode64 \catcode96 \the\catcode96
\newlinechar \the\newlinechar \endlinechar \the\endlinechar }
\xywarnifdefined\xycatcodes \def\xycatcodes{%
\catcode 9 10
\catcode35 6 \catcode 36 3 \catcode 38 4
\catcode43 12 \catcode 45 12 \catcode 46 12 \catcode 47 12
\catcode60 12 \catcode 61 12 \catcode 62 12
\catcode64 11 \catcode 96 12 }
\xycatcodes
\message{docmode,}
{\catcode`\|0 \xywarnifdefined|DOCMODE
\gdef|DOCMODE#1{\ifx(#1\relax \xycatcodes \expandafter\ignorespaces
\else \skipspecials@ \expandafter\docm@\fi}%
\xywarnifdefined\skipspecials@
\gdef\skipspecials@{%
\catcode`\\12 \catcode`\{12 \catcode`\}12 \catcode`\#12 \catcode`\%12
\catcode`\^^L12 \endlinechar`\^^J }%
\catcode`\/=12 \lccode`\/`\\%
\lccode`\D`\D \lccode`\O`\O \lccode`\C`\C \lccode`\M`\M \lccode`\E`\E
\lowercase{%
\xywarnifdefined\docm@ \gdef\docm@{\docm@i}%
\xywarnifdefined\docm@i \gdef\docm@i#1^^J{\docm@ii#1/DOCMODE\docm@iii}%
\xywarnifdefined\docm@ii
\gdef\docm@ii#1/DOCMODE{\def\next@{#1}\futurelet\next\docm@iii}%
\xywarnifdefined\docm@iii \gdef\docm@iii#1\docm@iii{%
\ifx\next\docm@iii \let\next\next@ \docecho@ \let\next@\docm@
\else\ifx\next@\empty \let\next@\docfinish@
\else \edef\next@{\noexpand\docm@iv\next@/DOCMODE#1\noexpand\docm@iv}%
\fi\fi \next@}%
\xywarnifdefined\docm@iv
\gdef\docm@iv#1/DOCMODE\docm@iv{\def\next{#1}\docecho@ \docm@}}%
\xywarnifdefined\docecho@ \global\let\docecho@\relax
\xywarnifdefined\docfinish@ \gdef\docfinish@{\xyuncatcodes|DOCMODE\next}}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
After giving an overview of the \XY-pic environment in \S??[env] we
document the basic concepts of \XY-picture construction in
\S??[basics], including the maintained `graphic state'. The
following sections give the precise syntax rules of the main \XY-pic
constructions: the position language in~\S??[pos], the object
constructions in~\S??[object], and the picture `decorations'
in~\S??[decor]. \S??[objectlib] presents the kernel repertoire of
objects for use in pictures; \S??[option] documents the interface to
\XY-pic options like the standard `feature' and `extension' options.
\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Details of the implementation are not discussed in this \APPENDIX\
but in the complete \TeX\-nical documentation~\cite{R94:XY-picCSTC}.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Section \S??[algo] documents the more complicated algorithms used to
compute directions, edges, and connections.
This \APPENDIX\ includes all of the text in the ``Basic
\XY-pictures'' reference manual~\cite{R94:XY-picRM}.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection*{Notation}
We will give descriptions of the "syntax" of pictures as \BNF??w[BNF]
rules; in explanations we will use upper case letters like $X$ and
$Y$ for <dimen>sions and lower case like $x$ and $y$ for <factor>s.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{The \XY-pic implementation}
??=[env]
This section briefly discusses the various aspects of the present
\XY-pic kernel implementation of which the user should be aware in
order to experiment with it.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Loading \XY-pic}
??=[env.loading]??w[loading]
\XY-pic is careful to set up its own environment in order to function
with a large variety of formats. For most formats a single line with
the command
$$
??c![\input xy]
$$
in the preamble of a document file should load the kernel (see
`integration with standard formats' below for variations possible
with certain formats, in particular \LaTeX~\cite{L94:LaTeX}).
The rest of this section describes things you must consider if you
need to use \XY-pic together with other macro packages, style
options, or formats. The less your environment deviates from plain
\TeX\ the easier it should be.
\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Consult the \TeX\-nical documentation~\cite{R94:XY-picCSTC} for the
exact requirements for other definitions to coexist with \XY-pic.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{File header:}
??w[file header]
Here is what actually happens in the header of |xy.doc|. It contains
the copyright message, protection against ??w![loading] the file more
than once, and then bootstrap code to handle category codes and the
??c![DOCMODE] format---we explain each separately below:
\DOCHEADER
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Privacy:}
??w[privacy]
\XY-pic will warn about control sequences it redefines---thus you can
be sure that there are no conflicts between \XY-pic-defined control
sequences, those of your format, and other macros, provided you
load??w[loading] \XY-pic last and get no ??w![warning
messages] like
$$
|XY-pic Warning: `|\dots|' redefined.|??w[redefined]
$$
In general the \XY-pic kernel will check all control sequences it
redefines "except" that (1)~generic temporaries like ??c![\next] are
not checked, (2)~predefined font identifiers (see~\S??[env.fonts])
are assumed intentionally preloaded, and (3)~some of the more exotic
control sequence names used internally (like |\dir{-}|) are only
checked to be different from ??c![\relax].
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is handled by ??c![\xywarnifdefined]---after we have ensured
that it is unique itself\footnote{This may seem paranoid but in fact
many inconvieniences in the \TeX\ world stem from the fact that
somebody copied somebody elses definition of, say,
{\tt\string\xywarnifdefined}, modified it, and then used it in
something that somehow got distributed! The `flat name space'
problem remains \TeX\ largest problem as a programming language in
this \TeX\ hackers opinion.}. ??c![\xydef@], ??c![\xylet@], and
|\xynew@{|<type>|}|??c[\xynew@] are abbreviations used to this end
throughout \XY-pic instead of ??c![\let], ??c![\def], and the
|\new|<type> commands.
Next some auxilliaries: |\xydefcsname@| is similar to |\xydef@|
except that it builds the control sequence with ??c![\csname] \dots\
??c![\endcsname] which means that it is |\relax| when undefined---there
is thus no way to prevent redefinition of control sequences bound to
??c![\relax]~\frowny.
\DOCMODE(
\xydef@\xydefcsname@#1{\DN@{#1}\DNii@##1{%
\ifx ##1\relax\else \xywarning@{`\string##1\string' redefined.}\fi \def##1}%
\expandafter\nextii@\csname\codeof\next@\endcsname}
\DOCMODE)
|\xyletcsnamecsname@| is to ??c![\let] one weird control sequence
be the same as another using several |\expandafter|s:
\DOCMODE(
\xydef@\xyletcsnamecsname@#1#2{\def\1{#1}\def\2{#2}\DN@##1##2{%
\ifx ##1\relax\else \xywarning@{`\string##1\string' redefined.}\fi
\let##1=##2}%
\expandafter\expandafter\expandafter\next@
\expandafter\csname\expandafter\codeof\expandafter\1\expandafter\endcsname
\csname\codeof\2\endcsname}
\DOCMODE)
Finally ??c![\codeof]: a useful hack used to allow any characters in
control sequences: |\codeof|<cs> expands to the characters of the
control sequence <cs> as a string of `other' characters, \ie, all of
category 12 and with a \verb*/ /$_{12}$ after every control sequence.
<cs> must be a macro or it blows up.
\DOCMODE(
\xywarnifdefined\codeof
\xywarnifdefined\codeof@
{\catcode`\:=12 \catcode`\>=12 % to ensure that all of :->< are other...
\gdef\codeof#1{\expandafter\codeof@\meaning#1<-:}
\gdef\codeof@#1:->#2<-:{#2}}
\DOCMODE)
Similarly ??c![\charof@]: returns the character with category 12; it
must have category 11 or 12 for this to work. Useful when a
character is |\let| to some control sequence.
\DOCMODE(
\xydef@\charof#1{\expandafter\c@arof@\meaning#1}
\xywarnifdefined\charof@
{\let\1=\gdef \let\2=\catcode \2`\t=12 \2`\h=12 \2`\e=12
\1\c@arof@ the #1 #2{#2}}
\DOCMODE)
\TODO: Actually the best would be to have a unique prefix, say |xy@|,
used for all private internal control sequences\dots
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Category codes:}
Unfortunately the situation is complicated by the flexibility of
\TeX's input format. The culprit is the `??w![category code]'
concept of \TeX\ (\cf~\cite[p.37]{K84:TeXbook}): when loaded \XY-pic
requires the characters {\tt\char32}|\{}%| (the first is a space) to
have their standard meaning and all other printable characters to
have the "same category as when \XY-pic will be used"---in particular
this means that (1)~you should surround the ??w![loading] of \XY-pic
with ??c![\makeatother] \dots\ ??c![\makeatletter] when loading it
from within a \LaTeX\ package, and that (2)~\XY-pic should be loaded
after files that change category codes (like the |german.sty| that
makes |"| active??w[active characters]).
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We define ??c![\xyuncatcodes] to restore the current catcodes, and
|\xycatcodes| to install our own.
Here is an exact list of the category codes which \XY-pic requires
(all standard in plain \TeX):
$$
\vcenter{\tabskip=.5em plus1fil \halign to\displaywidth{#\hfil&&\hfil#\hfil\cr
character(s) &|\| &|{| &|}| &CR &TAB SP&|A|--|Z| |a|--|z| &|0|--|9| &|%| \cr
category code & 0 & 1 & 2 & 5 & 10 & 11 & 12 & 14 \cr}
}$$
Furthermore none of the remaining printable ASCII characters
$$
|!"#$&'()*,/:;?@[]^_`||~|
$$
may be of category 0, 1, 2, 9, 14, or 15, because all should be
tokens allowed in the replacement text of a |\def|---this also means
that they may not be active characters defined to be ``|\outer|''!
All other catcodes needed are established using ??c![\xycatcodes]
defined above---this is the reason the macros must be loaded at a
time where the category codes are stable (otherwise it will make them
stable!).
Internally \XY-pic enforces the following category codes:
$$
\vcenter{\tabskip=.5em plus1fil \halign to\displaywidth{#\hfil&&\hfil#\hfil\cr
character &|#|&|$|&|&|&|'|&|+|&|-|&|.|&|<|&|=|&|>|&|@|&|`|\cr
ASCII code & 35& 36& 38& 39& 43& 45& 46& 60& 61& 62& 64& 96\cr
category code& 6 & 3 & 4 & 12& 12& 12& 12& 12& 12& 12& 11& 12\cr
abbreviation&|HASH|&|DOLL|&|AND|&|RQ|&|PLUS|&|DASH|&|DOT|
&|LT|&|EQ|&|GT|&|AT|&|LQ|\cr}
}$$
with special control sequences named |\add|<abbreviation>|@| that
take an argument and expand to it followed by the original character
token, \ie, many tests throughout the program look like |\addDOT@|
|\ifx| |\next| \dots
Here is the code to build the special |\add|\dots|@| control
sequences---this of course involves reestablishing the original
codes.
\DOCMODE(
\xydef@\xymakeADD@#1#2 #3 {\ifnum\catcode#3=6 \xydef@#1##1{##1#2#2}%
\else\xydef@#1##1{##1#2}\fi}
\def\next{\xymakeADD@\addAT@}
\xyuncatcodes
\next @ 64 \catcode 64 11
\xymakeADD@\addHASH@ # 35
\xymakeADD@\addDOLL@ $ 36
\xymakeADD@\addAND@ & 38
\xymakeADD@\addRQ@ ' 39
\xymakeADD@\addPLUS@ + 43
\xymakeADD@\addDASH@ - 45
\xymakeADD@\addDOT@ . 46
\xymakeADD@\addLT@ < 60
\xymakeADD@\addEQ@ = 61
\xymakeADD@\addGT@ > 62
\xymakeADD@\addLQ@ ` 96
\xycatcodes
\DOCMODE)
The last block of the header bootstraps the ``??c![DOCMODE] format''
used in |.doc| variants of \XY-pic macro files in order to keep
documentation and macros together in a literal programming style
(this is redundant in the |xy.tex| macro file where all instances of
|DOCMODE| have been eliminated (see chapter \S??g[Makefile] for how
this is accomplished) but it is included anyway since users may load
options still in |DOCMODE| format). The details of |DOCMODE| are
described in |xydoc.sty|, a special \LaTeX\ package used to typeset
\XY-pic documentation; please read it if you intend to write \XY-pic
options.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Integration with standard formats}
??w[formats]
The ??w![integration] with various formats is handled by the
|xyidioms.tex| file and the integration as a \LaTeX~\cite{L94:LaTeX}
package by |xy.sty|:
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We input |xyidioms.tex| from the kernel:
\DOCMODE(
\input xyidioms
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subparagraph{xyidioms.doc:}
??c[xyidioms.doc]
\inputdoc!{xyidioms.doc}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subparagraph{xy.sty:}
??c[xy.sty]
%
If you use ??w![\LaTeX] then this file makes it possible to
load??w[loading] \XY-pic as a `??w![package]' using the
\LaTeXe~\cite{L94:LaTeX} |\usepackage| command:
%
\begin{defs1}
|\usepackage| |[|<option>|,|\dots|]| |{xy}|
\end{defs1}
\noindent\unskip
%
where the <option>s will be interpreted as if passed to |\xyoption|
(\cf~\S??[option]); furthermore options that require special
activation will also be activated when loaded this way (\eg,
including |cmtip| in the <option> list will not only perform
|\xyoption| |{cmtip}| but also |\Use|\-|Computer|\-|Modern|\-|Tips|).
Driver package options (\cf~\cite[table 11.2, p.317]{GMS94:LaTeXC})
will invoke the appropriate backend (\cf~\S??g[:ps]).
The file also works as a \LaTeX~2.09~\cite{L86:LaTeX} `??w![style
option]' although you will have to load options with the \XY-pic
mechanism.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Here is the raw source of |xy.sty|.
\inputdoc0{xy.sty}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Logo, version, and messages}
??=[env.logo]
Loading \XY-pic prints a ??w![banner] containing the version and
author of the kernel; small progress ??w![messages] are printed when
each major division of the kernel has been loaded. Any options
loaded will announce themself in a similar fashion.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Of these, |\stripRCS| is a very useful hack for extracting the first
component of an RCS |$|\dots|$| keyword value.
\DOCMODE(
\xydef@\stripRCS$#1${\stripRCS@#1: @@ @@@}
\xydef@\stripRCS@#1: #2@ #3@@@{%
\ifx @#2\string?\else\ifx :#2\else\stripRCS@@#2\fi\fi}
\xydef@\stripRCS@@#1 #2: @{#1}
\edef\next{\stripRCS$Revision: 2.12 $}
\edef\next@{\stripRCS$Locker: $}
\xylet@\xyversion=\next
\def\next{ @}\ifx\next\next@\else \edef\xyversion{\xyversion.\next@}\fi
\edef\next{\stripRCS$Date: 1994/10/25 11:55:12 $}
\xylet@\xydate=\next
\def\next{ @}\ifx\next\next@\else\edef\xydate{\xydate\space(work version)}\fi
\xydef@\XYgreet@{%
\W@{}%
\W@{ XY-pic version \xyversion\space<\xydate>}%
\W@{ Copyright (c) 1991-1994 by Kristoffer H. Rose <kris@diku.dk>}%
\W@{ XY-pic is free software: see the User\string's Guide for details.}%
\W@{}}
\XYgreet@
\expandafter\everyjob\expandafter{\the\everyjob\XYgreet@}
\message{Loading kernel:}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
If you refer to \XY-pic in your written text (please do~\smiley~)
then you can use the command ??c![\Xy]|-pic| to typeset the
``??w![\XY-pic]'' ??w![logo]. The ??w![version] of the kernel is
typeset by |\xyversion| and the release date by |\xydate| (as found
in the banner). By the way, the \XY-pic "name"\footnote{No
description of a \TeX\ program is complete without an explanation of
its name.} originates from the fact that the first version was
little more than support for $(x,y)$ coordinates in a configurable
coordinate system where the main idea was that "all" operations could
be specified in a manner independent of the orientation of the
coordinates. This property has been maintained except that now the
package allows explicit absolute orientation as well.
\DOCMODE(
\xydef@\XY{\leavevmode
\hbox{\kern-.1em X\kern-.3em\lower.4ex\hbox{Y\kern-.15em}}}
\xylet@\Xy=\XY
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Messages that start with ``|XY-pic| ??c![Warning]'' are indications
that something needs your attention; an ``|XY-pic| ??c![Error]'' will
stop \TeX\ because \XY-pic does not know how to proceed.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We use the input line number if available and rudimentary help in the
form of a reference to the manual if no specific help string is
given. ??c![\newlinechar] is set locally to |^^J| while writing such
that messages of several lines can be written.
\DOCMODE(
\message{messages;}
\xywarnifdefined\thelineno@
\ifx\inputlineno\undefined \edef\thelineno@{\string?}
\else \def\thelineno@{\the\inputlineno}\fi
\xydef@\xytracelineno@{ \string[\jobname:\thelineno@\string]}
\xydef@\xywarning@#1{{\newlinechar=`\^^J%
\W@{}\W@{XY-pic Warning: #1\xytracelineno@.}\W@{}}}
\xydef@\xyerror@#1#2{{\DNii@{#2}\newlinechar=`\^^J%
\ifx\nextii@\empty \errhelp{See the XY-pic manual for further information.}%
\else \errhelp{#2}\fi
\errmessage{XY-pic error: #1}}}
\DOCMODE)
Finally one that I hope will never get expanded~\frowny
\DOCMODE(
\xydef@\xybug@#1{{\newlinechar=`\^^J%
\errhelp{This is a bug in XY-pic and should not happen!^^J%
If it did then please send a bug report with the offending XY-pic code^^J%
to the author of XY-pic, kris@diku.dk.}%
\errmessage{XY-pic BUG: #1 -- notify kris@diku.dk.}}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Fonts}
??=[env.fonts]
The \XY-pic kernel implementation makes its drawings using five
specially designed ??w![fonts]:%
%
??w[dashes]??w[tips]??w[circles]??w[hooks]??w[squiggles]
$$
\begin{array}{\otherbar c\otherbar c\otherbar l\otherbar}
\hline
\hbox{Font} & \hbox{Characters} & \hbox{Default}\\
\hline
??c![\xydashfont]& \hbox{dashes} & ??c![xydash10]\\
??c![\xyatipfont]& \hbox{arrow tips, upper half} & ??c![xyatip10]\\
??c![\xybtipfont]& \hbox{arrow tips, lower half} & ??c![xybtip10]\\
??c![\xybsqlfont]& \hbox{quarter circles for\qquad} & ??c![xybsql10]\\
& \hbox{\qquad hooks and squiggles} &\\
??c![\xycircfont]& \hbox{$1/8$ circle segments} & ??c![xycirc10]\\
\hline
\end{array}
$$
The first four contain variations of characters in a large number of
directions, the last contains 1/8 circle segments.
\paragraph*{Note:}
The default fonts are not part of the \XY-pic kernel "specification":
they just set a standard for what drawing capabilities should at
least be required by an \XY-pic implementation. Implementations
exploiting capabilitites of particular output devices are in use.
Hence the fonts are only loaded by \XY-pic if the control sequence
names are undefined---this is used to preload them at different sizes
or prevent them from being loaded at all.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
To be more precise, \XY-pic requires ??c![\xydashfont] to be a
"??w![semidirectional]" font as \MF\ will generate with the driver
file ??c![xyd2.mf]---this is very important because the "??w![italic
corrections]" of the characters in this particular font are used to
approximate trigonometric computations, so if you replace
|\xydashfont| be sure to replace it with another semidirectional
font! Similarly, the three fonts |\xyatipfont|, |\xybtipfont|, and
|\xybsqlfont| should be "??w![directional]" as \MF\ will generate
with the driver file ??c![xyd.mf].
Finally, |\xycircfont| should contain $1/8$ circle segments of
various radii as described in |xycirc10.mf|.
The following code loads the fonts "unless it was already loaded" and
defines some associated dimensions for |\xydashfont| and
|\xybsqlfont|: for each of these $f$ we define $f_\ell$ as the length
of a unit in the current direction (used when juxtaposing for
connections), $f_h$ as the height of the unit (used for several
parallel connections), and $f_w$ as the `line width' of the unit (to
know how to interface to rules).
\DOCMODE(
\message{fonts;}
\xydef@\xyfont@#1{\ifx#1\undefined \DN@{\global\font#1}\expandafter\next@
\else \xywarning@{Using previously loaded \string#1\space font.}\fi}
\xyfont@\xydashfont=xydash10
\xydef@\xydashl@{\fontdimen6\xydashfont}
\xydef@\xydashh@{\fontdimen5\xydashfont}
\xydef@\xydashw@{\fontdimen8\xydashfont}
\xyfont@\xyatipfont=xyatip10
\xyfont@\xybtipfont=xybtip10
\xyfont@\xybsqlfont=xybsql10
\xydef@\xybsqll@{\fontdimen6\xybsqlfont}
\xydef@\xybsqlh@{\fontdimen5\xybsqlfont}
\xydef@\xybsqlw@{\fontdimen8\xybsqlfont}
\xyfont@\xycircfont=xycirc10
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Allocations}
??=[env.alloc]??w[allocation]
One final thing that you must be aware of is the fact that \XY-pic
allocates a significant number of dimension registers and some
counters, token registers, and box registers, in order to represent
the state and do computations. The \XY-pic v.\xyversion\ kernel
allocates 6~counters, 27~dimensions, 2~box registers, 3~token
registers, 1~read channel, and 1~write channel (when running under
plain \TeX; under \LaTeX\ and \AMS-\TeX\ slightly less is allocated
because the provided temporaries are used). Options may allocate
further registers.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\DOCMODE(
\message{allocations:}
\DOCMODE)
See \S??[env.loading] for scratch register allocations.
\paragraph*{Picture state:}
These realise the picture state as described in \S??[basics.state]:
$c$, $p$, the "base", and the picture size:
\DOCMODE(
\message{state,}
\xynew@{dimen}\Xc
\xynew@{dimen}\Yc
\xynew@{dimen}\Uc
\xynew@{dimen}\Dc
\xynew@{dimen}\Lc
\xynew@{dimen}\Rc
\xynew@{toks}\Edgec
\xynew@{dimen}\Xp
\xynew@{dimen}\Yp
\xynew@{dimen}\Up
\xynew@{dimen}\Dp
\xynew@{dimen}\Lp
\xynew@{dimen}\Rp
\xynew@{toks}\Edgep
\xynew@{dimen}\Xorigin \Xorigin=\z@
\xynew@{dimen}\Yorigin \Xorigin=\z@
\xynew@{dimen}\Xxbase \Xxbase=1mm
\xynew@{dimen}\Yxbase \Yxbase=\z@
\xynew@{dimen}\Xybase \Xybase=\z@
\xynew@{dimen}\Yybase \Yybase=1mm
\xynew@{dimen}\Xmin
\xynew@{dimen}\Ymin
\xynew@{dimen}\Xmax
\xynew@{dimen}\Ymax
\DOCMODE)
\paragraph*{Drop and connect:}
|\lastobjectbox@| stores the most recently dropped
object.??c[\lastobject]
\DOCMODE(
\xynew@{box}\lastobjectbox@
\DOCMODE)
|\zerodotbox@|??c[\zerodot] is of zero size with a `dot' in the form
of a rule the width and height as the line width of the line font.
\DOCMODE(
\xynew@{box}\zerodotbox@
\setbox\zerodotbox@=\hbox{\dimen@=.5\xydashw@
\kern-\dimen@ \vrule width\xydashw@ height\dimen@ depth\dimen@}
\wd\zerodotbox@=\z@ \ht\zerodotbox@=\z@ \dp\zerodotbox@=\z@
\DOCMODE)
\paragraph*{Direction state:}
The ??w![direction] state is rather complicated and described in
detail in~\S??[algo.direction].
\DOCMODE(
\message{direction,}
\xynew@{dimen}\dX
\xynew@{dimen}\dY
\xydef@\sdX{}
\xydef@\sdY{}
\xynew@{count}\K \K=1024
\xynew@{count}\KK@ \KK@=32
\xynew@{count}\Direction
\xynew@{dimen}\K@dXdY
\xynew@{dimen}\K@dYdX
\xydef@\cosDirection{}
\xydef@\sinDirection{}
\xywarnifdefined\DirectionChar
\xywarnifdefined\SemiDirectionChar
\DOCMODE)
\paragraph*{Miscellaneous:}
Finally some generic allocations used in the following:
\DOCMODE(
\xynew@{read}\xyread@ % for `safe input'
\xynew@{write}\xywrite@ % for `saving' to .xyc file
\xynew@{count}\csp@ % for `control stack pointer'
\xynew@{dimen}\quotPTK@ % for `fractions'
\DOCMODE)
The required temporaries are defined by |xyidioms.tex|.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Utility macros}
??=[env.util]
Finally we define some utility macros.
\DOCMODE(
\message{utility macros;}
\DOCMODE)
\paragraph*{Simple queue:}
??w[queue]
Just appending and prepending to the ??c![\toks@] list.
\DOCMODE(
\xydef@\addtotoks@#1{\toks@=\expandafter{\the\toks@#1}}
\xydef@\prependtotoks@#1{%
\expandafter\def\expandafter\prependtotoks@@\expandafter{\the\toks@}%
\toks@=\expandafter\expandafter\expandafter{%
\expandafter\prependtotoks@@\the\toks@}}
\xylet@\prependtotoks@@=\relax
\DOCMODE)
\paragraph*{Safe input:}
Check that file is available before input.
\DOCMODE(
\xydef@\xyinputorelse@#1#2{\openin\xyread@=#1 %
\ifeof\xyread@ \DN@{#2}\else \DN@{\closein\xyread@\input#1 }\fi \next@}
\DOCMODE)
\paragraph*{Continuation stack:}
This is used to `??w![enter]' a new ??w![context] and `??w![leave]'
to the previous context. It works as a stack defining a control
sequence for each level, thus using a counter as the stack pointer.
Defines the following
%
\begin{defs}
|\csp@| & `Continuation Stack Pointer' \cr
|\enter@{|<code>|}| & Enter new block with <code> expanded as continuation\cr
|\nter@{|<code>|}| & Enter new block with<code> as continuation\cr
|\dontleave@| & Execute continuation without leaving block\cr
|\unenter@| & Leave block without executing its continuation\cr
|\leave@| & Leave block (execute its continuation)\cr
\end{defs}
So |\enter@{}\leave@| is a noop and |\leave@| is the same as
|\dontleave@\unenter@|.
\DOCMODE(
\global\csp@=\z@
\xydef@\enter@#1{\global\advance\csp@\@ne
\expandafter\xdef\csname cs@\number\csp@\endcsname{#1}\ignorespaces}
\xydef@\nter@#1{\global\advance\csp@\@ne
\expandafter\gdef\csname cs@\number\csp@\endcsname{#1}\ignorespaces}
\xydef@\dontleave@{\csname cs@\number\csp@\endcsname}
\xydef@\unenter@{\global\advance\csp@\m@ne}
\xydef@\leave@{\expandafter\unenter@\csname cs@\number\csp@\endcsname}
\DOCMODE)
\paragraph*{Fractions:}
??w[fraction computation]
Below we often use a factor on the form of a quotient $A/B$. Here is
a hack to get it; it is not very precise but suffices for our needs.
%
\begin{defs}
|\quotient@| <cs> |{|$A$|}| |{|$B$|}| &
Defines <cs> to expand (immediately) to the factor corresponding to
$A/B$; $A$, $B$ must be dimensions where $\abs{A}\lt|\maxdimen|/|KK|$
and $\abs{B}\gt|KK|$
\cr
|\quotient@@| <cs> |{|$A$|}| |{|$B$|}| &
Same, but uses $8|KK|$ for |KK|.
\cr
\end{defs}
%
"Notes": (1) If |\c| is a count register, then |{1\c}| is a legal
dimension. (2) Really computes
$$
\left((A*\abs{|KK|}) / (B/\abs{|KK|})\right) * \left(|1pt|/\abs{|K|}\right)
$$
and then defines <cs> to expand to the resulting |pt| value. This
means that results are only reasonable for
$\abs{A}\ll|\maxdimen|/|KK|$ and $\abs{B}\gg|KK|$.
\DOCMODE(
\quotPTK@=\p@ \divide\quotPTK@\K
\xylet@\quotsign@@=\empty
\xywarnifdefined\removePT@
{\catcode`p=12 \catcode`t=12 \gdef\removePT@#1pt{#1}}
\xydef@\quotient@#1#2#3{\A@=#2\relax \B@=#3\relax
\ifdim\A@<\z@\def\quotsign@@{-}\else\def\quotsign@@{+}\fi
\ifdim\quotsign@@\A@<15pt \multiply\A@\K
\else\ifdim\quotsign@@\A@<511pt \multiply\A@\KK@ \divide\B@\KK@
\else \divide\B@\K \fi\fi
\ifdim\ifdim\B@<\z@-\fi\B@<\quotPTK@ \xywarning@{division overflow}%
\else \advance\A@.5\B@ \divide\A@\B@ \fi
\multiply\A@\quotPTK@ \edef#1{\expandafter\removePT@\the\A@}}
\xydef@\quotient@@#1#2#3{\A@=#2\relax \B@=#3\relax
\multiply\A@\KK@ \divide\B@\KK@ \divide\B@ 8 %
\ifdim\B@=\z@\else \advance\A@.5\B@ \divide\A@\B@ \fi
\B@=.125\quotPTK@ \multiply\A@\B@ \edef#1{\expandafter\removePT@\the\A@}}
\DOCMODE)
\paragraph*{Loops:}
\XY-pic uses its own |\loop@| to avoid interference with plain
??c![\loop].
\DOCMODE(
\xydef@\loop@#1\repeat@{\def\body@{#1}\iterate@}\xylet@\repeat@=\fi
\xydef@\iterate@{\body@\expandafter\iterate@\else\fi}
\DOCMODE)
\paragraph*{Execution:}
All ??w![execution] of \XY-commands should be `indirect', \ie,
execute
$$
|\xy@{|<source>|}{|<internal commands>|}|
$$
where the <internal commands> directly do the desired operation(s).
This is used for tracing and can be used to separate parsing and
execution by changing |\xy@|; |\oxy@| is kept stable such that
|\let\xy@=\oxy@| will reestablish a sane state.
\DOCMODE(
\xydef@\xyinitial@#1#2{\DN@{#1}%
\xyerror@{XY-pic command used out of context: \codeof\next@}{}}
\xylet@\xy@=\xyinitial@
\xylet@\oxy@=\xy@
\DOCMODE)
This is also used to check whether an \XY-picture is already
active; use as |\if\inxy@|\dots|\else|\dots|\fi|:
\DOCMODE(
\xydef@\inxy@{T\ifx\xy@\xyinitial@ F\else T\fi}
\DOCMODE)
The final execution command is a trick used to put bits of the user's
input inside the |\next@| scratch macro "with the user's catcodes
intact": |\xy@@ix@{|\dots|}| is the same as
|\xy@@{\global\toks9={|\dots|}}| except for the category codes used
for the \dots.
\DOCMODE(
\xydef@\xyxy@@ix@{\begingroup
\xyuncatcodes\afterassignment\endgroup\global\toks9=}
\DOCMODE)
This to save some tokens -- maybe not worth it:
\DOCMODE(
\xydef@\xy@@{\xy@{}}
\DOCMODE)
Finally this to establish a sane state -- only use within a group!
\DOCMODE(
\xydef@\plainxy@{\let\xy@=\xyxy@ \let\oxy@=\xy@ \let\xy@@ix@=\xyxy@@ix@}
\DOCMODE)
\TODO: Clean up all uses of these such that <source> is always that
and only that. Define a method for `inner' \aka\ `implied' <source>
that doesn't really count in that it is a consequence of some other
source\dots
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Picture basics}
??=[basics]
The basic concepts involved when constructing \XY-pictures are
positions and objects, and how they constitute a state used by the
graphic engine.
The general structure of an \XY-picture is as follows:
%
\begin{defs1}
%
??c![\xy] <pos> <decor> ??c![\endxy] \cr
%
\end{defs1}
\noindent\unskip
%
builds a box with an \XY-picture (\LaTeX\ users may substitute
|\begin{xy}| \dots\ |\end{xy}| if they prefer). <pos> and <decor>
are components of the special `graphic language' which \XY-pictures
are specified in. We explain the language components in general
terms in this \S\ and in more depth in the following \S\S.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The code for the |\xy|\dots|\endxy| command is presented last in this
section.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Positions}
??=[basics.pos]
All "??w![positions]" may be written |<|$X$|,|$Y$|>| where ??w![$X$]
is the \TeX\ dimension distance "right" and ??w![$Y$] the distance
"up" from the "??w![zero position]" ??c![0] of the \XY-picture (|0|
has coordinates |<0mm,0mm>|, of course). The zero position of the
\XY-picture determines the box produced by the |\xy|\dots|\endxy|
command together with the four parameters ??w![$X_{\min}$],
??w![$X_{\max}$], ??w![$Y_{\min}$], and ??w![$Y_{\max}$] set such
that all the objects in the picture are `contained' in the following
rectangle:
$$
\xy.(-13,-12).(25,15)="b"*\frm{-}*\dir{o},
"b"+<2pc,-.8pc>*{|0|};"b"*{}**\dir{.},
"b"+L+<-2pc,-.8pc>*!UR\txt{\TeX\ reference point};"b"+L*\dir{*}**\dir{.},
"b"+0;
"b"+L **\dir{-} ?>*\dir{>} ?*++!U{X_{\min}},
"b"+R **\dir{-} ?>*\dir{>} ?(.7)*++!U{X_{\max}},
"b"+D **\dir{-} ?>*\dir{>} ?(.7)*++!L{Y_{\min}},
"b"+U **\dir{-} ?>*\dir{>} ?*++!L{Y_{\max}}
\endxy
$$
where the distances follow the ``up and right~$\gt0$'' principle,
\eg, the indicated \TeX\ reference point has coordinates
|<|$X_{\min}$|,0pt>| within the \XY-picture. The zero position does
not have to be contained in the picture, but $X_{\min} \le X_{\max}
\land Y_{\min} \le Y_{\max}$ always holds. The possible positions
are described in detail in~\S??[pos].
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Objects}
??=[basics.object]
The simplest form of putting things into the picture is to `drop' an
"??w![object]" at a position. An object is like a \TeX\ box except
that it has a general "??w![Edge]" around its reference point---in
particular this has the "??w![extents]" (\ie, it is always contained
within) the dimensions ??w![$L$], ??w![$R$], ??w![$U$], and ??w![$D$]
away from the reference point in each of the four directions left,
right, up, and down. Objects are encoded in \TeX\ boxes using the
convention that the ??w![\TeX\ reference point] of an object is at
its left edge, thus shifted |<|${-}L$|,0pt>| from the center---so a
\TeX\ box may be said to be a rectangular object with $L=|0pt|$.
Here is an example:
$$
\let\objectstyle=\scriptstyle
\xy(0,0).(-10,-5).(15,8)*\frm{-}="box"*\dir{o}+0;
"box"+L*{}**\dir{.}?*{L},
"box"+R*{}**\dir{.}?*{R},
"box"+D*{}**\dir{.}?*{D},
"box"+U*{}**\dir{.}?*{U},
"box"+L+<-2pc,-.8pc>*!UR\hbox{\TeX\ reference point};
"box"+L*{\bullet}*{}**\dir{.},
\endxy
$$
The object shown has a rectangle edge but others are available even
though the kernel only supports rectangle and circle edges. It is
also possible to use entire \XY-pictures as objects with a rectangle
edge, |0| as the reference point, $L={-X_{\min}}$, $R={X_{\max}}$,
$D={-Y_{\min}}$, and $U={Y_{\max}}$. The commands for objects are
described in~\S??[object].
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Connections}
??=[basics.connect]
Besides having the ability to be dropped at a position in a picture,
all objects may be used to "??w![connect]" the two current objects of
the state, \ie, $p$ and $c$. For most objects this is done by
`filling' the straight line between the centers with as many copies
as will fit between the objects:
$$
\let\objectstyle=\scriptscriptstyle
\xy*=<12pt>[o]{p}="P"*\cir{} ; (60,15)*=<18pt,8pt>{c}="C"*\frm{-}**\dir{--}
%
**\xybox{(0,0).(-3,-2).(2,3)*\frm{.}="box"*\dir{o}+0;
"box"+L**\dir{.}?*{L},
"box"+R**\dir{.}?*{R},
"box"+D**\dir{.}?*{D},
"box"+U**\dir{.}?*{U}},
\endxy
$$
The ways the various objects connect are described along with the
objects.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Decorations}
??=[basics.decor]
When the ??c![\xy] command reaches something that can not be
interpreted as a continuation of the position being read, then it is
expected to be a "??w![decoration]", \ie, in a restricted set of
\TeX\ commands which add to pictures. Most such commands are
provided by the various "user options" (\cf~\S??[option])---only a
few are provided within the kernel to facilitate programming of such
options (and user macros) as described in~\S??[decor].
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{The \XY-pic state}
??=[basics.state]
Finally we summarise the user-accessible parts of the
??w![\XY-picture state] of two positions together with the
last object associated with each: the "previous", ??w![$p$], is the
position |<|??w![$X_p$]|,| ??w![$Y_p$]|>| with the object
??w![$L_p$], ??w![$R_p$], ??w![$D_p$], ??w![$U_p$], ??w![$"Edge"_p$],
and the "current", ??w![$c$], is the position |<|??w![$X_c$]|,|
??w![$Y_c$]|>| with the object ??w![$L_c$], ??w![$R_c$], ??w![$D_c$],
??w![$U_c$], ??w![$"Edge"_c$].
Furthermore, \XY-pic has a configurable "??w![cartesian coordinate
system]" described by an "origin" position |<|??w![$X_"origin"$]|,|
??w![$Y_"origin"$]|>| and two "base vectors" |<|??w![$X_"xbase"$]|,|
??w![$Y_"xbase"$]|>| and~|<|??w![$X_"ybase"$]|,|
??w![$Y_"ybase"$]|>|, and accessed by the usual notation using
parenthesis:
$$
\arraycolsep=.25em \begin{array}{rclll}
|(|x|,|y|)| & = & |<| & X_"origin" + x*X_"xbase" + y*X_"ybase" & |,| \\
& & & Y_"origin" + x*Y_"xbase" + y*Y_"ybase" & |>| \\
\end{array}
$$
This is explained in full when we show how to set the base in
note~??[base] of \S??[pos].
Finally typesetting a connection will setup a ``??w![placement
state]'' for referring to positions on the connection that is
accessed through a special |?| position construction; this is also
discussed in detail in \S??[pos].
The \XY-pic "??w![state]" consists of all these parameters
together. They are initialised to zero except for
$X_"xbase"=Y_"ybase"=|1mm|$. The dimension parameters are directly
available as \TeX\ |\dimen| registers with the obvious names:
??c![\Xmin], ??c![\Xmax], ??c![\Ymin], and ??c![\Ymax]; ??c![\Xp],
??c![\Yp] ??c![\Dp], ??c![\Up], ??c![\Lp], and ??c![\Rp]; ??c![\Xc],
??c![\Yc] ??c![\Dc], ??c![\Uc], ??c![\Lc], and ??c![\Rc];
??c![\Xorigin], ??c![\Yorigin], ??c![\Xxbase], ??c![\Yxbase],
??c![\Xybase], and ??c![\Yybase].
\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The edges are not directly available (but see the technical
documentation for how to access them).
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The edges are are available to the programmer as token lists; see
\S??[algo.edge] for details.
\subparagraph*{Procedure:}
??c![\xy]\ \dots\ ??c![\endxy] builds an object from an \XY-pic <pos>
<decor> sequence as follows: (??_[xy1])~|\xy| starts the |\hbox| to
contain the \XY-picture, (??_[xy2])~starts an inner box to be resized
appropriately later, sets |\xy@| to just execute immediately, and
makes a fresh scope for global internal names, and
(??_[xy3])~initialises the \XY-pic state (setting the size to a
ridiculously large negative value) and passes control to the <pos>
parser.
\DOCMODE(
\message{pictures: \string\xy,}
\xydef@\xy{\hbox\bgroup \aftergroup\xycheck@end %?*[xy1]
\setboxz@h\bgroup %?*[xy2]
\plainxy@
\Xc=\z@ \Yc=\z@ \czeroEdge@ %?*[xy3]
\Xp=\z@ \Yp=\z@ \Up=\z@ \Dp=\z@ \Lp=\z@ \Rp=\z@ \Edgep={\zeroEdge}%
\Xmin=\hsize \Xmax=-\hsize \Ymin=\hsize \Ymax=-\hsize
\POS}
\xydef@\czeroEdge@{\Uc=\z@ \Dc=\Uc \Lc=\Uc \Rc=\Uc \Edgec={\zeroEdge}}
\xydef@\xyxy@#1#2{#2}
\DOCMODE)
When finished |\endxy| does a |\relax| to disable any parser still
active and (??_[endxy1])~resets the size of the generated box to zero
if no (unhidden) objects were inserted, and (??_[endxy2])~defines a
command to end both the temporary and the `proper' box and set its
size correctly---this uses ??c![\edef] to expand the required
dimensions used within the temporary box before leaving the two
groups (namely the temporary box and the `proper' box).
\DOCMODE(
\xydef@\endxy{\relax
\dimen@=\Ymax \advance\dimen@-\Ymin %?*[endxy1]
\ifdim\dimen@<\z@ \dimen@=\z@ \Ymin=\z@ \Ymax=\z@ \fi
\dimen@=\Xmax \advance\dimen@-\Xmin
\ifdim\dimen@<\z@ \dimen@=\z@ \Xmin=\z@ \Xmax=\z@ \fi
\edef\tmp@{\egroup %?*[endxy2]
\setboxz@h{\kern-\the\Xmin\boxz@}%
\ht\z@=\the\Ymax \dp\z@=-\the\Ymin \wdz@=\the\dimen@ \boxz@
\egroup \noexpand\xy@end
\Uc=\the\Ymax \Dc=-\the\Ymin \Lc=-\the\Xmin \Rc=\the\Xmax}\tmp@}
\DOCMODE)
If an |\xy| is not properly closed by an |\endxy| then the error
message is produced. This happens if (a)~too many |\xy|s or (b)~too
many |\endxy|s or (c)~if there is the correct number of each but the
grouping becomes unbalanced due to a misplaced |}| or |\egroup|.
\DOCMODE(
\xydef@\xycheck@end{\xyFN@\xycheck@end@}
\xydef@\xycheck@end@{\ifx\next\xy@end\DN@\xy@end{}\else\DN@{\xy@end}\fi\next@}
\xydef@\xy@end{%
\xyerror@{An \string\xy\space environment is not closed correctly.}%
{I expected \string\endxy. You probably have an umatched {} grouping.}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Positions}
??=[pos]
\DOCMODE(
\message{positions,}
\DOCMODE)
A <pos>ition is a way of specifying locations as well as dropping
objects at them and decorating them---in fact any aspect of the
\XY-pic state can be changed by a <pos> but most will just change the
coordinates and/or shape of~$c$.
\begin{figure*}[tp]
\vss
\begin{syntax}
??w![<pos>]
&\iss & <coord>
& $c\from<coord>$
\cr
&\orr & <pos> ??c![+] <coord>
& $c \from <pos> + <coord>$??^[arithmetic]
\cr
&\orr & <pos> ??c![-] <coord>
& $c \from <pos> - <coord>$??^[arithmetic]
\cr
&\orr & <pos> ??c![!] <coord>
& $c\from<pos>$ then ??!^[skew] $c$ by <coord>
\cr
&\orr & <pos> ??c![.] <coord>
& $c\from<pos>$ but also ??!^[covering] $<coord>$
\cr
&\orr & <pos> ??c![,] <coord>
& $c\from<pos>$ then $c\from<coord>$
\cr
&\orr & <pos> ??c![;] <coord>
& $c\from<pos>$, swap $p$ and $c$, $c\from<coord>$
\cr
&\orr & <pos> ??c![:] <coord>
& $c\from<pos>$, set ??!^[base], $c\from<coord>$
\cr
&\orr & <pos> ??c![::] <coord>
& $c\from<pos>$, $"ybase"\from c-"origin"$, $c\from<coord>$
\cr
&\orr & <pos> ??c![*] <object>
& $c\from<pos>$, ??!^[drop] <object>
\cr
&\orr & <pos> ??c![**] <object>
& $c\from<pos>$, ??!^[connect] using <object>
\cr
&\orr & <pos> ??c![?] <place>
& $c\from<pos>$, $c\from\hbox{??!^[<place>]}$
\cr
&\orr & <pos> <stacking>
& $c\from<pos>$, do <stacking>
\cr
&\orr & <pos> <saving>
& $c\from<pos>$, do <saving>
\cr
\noalign{\smallbreak}
%
??w![<coord>]
&\iss & <vector>
& <pos> is <vector> with zero size
\cr
&\orr & <empty> \orr\ ??c![c]
& reuse last $c$ (do nothing)
\cr
&\orr & ??c![p]
& $p$
\cr
&\orr & ??c![x] \orr\ ??c![y]
& ??!^[axis intersection] with $\overline{pc}$
\cr
&\orr & ??c![s]<digit> \orr\ |s{|<number>|}|
& ??!^[stack] position <digit> or <number> below the top
\cr
&\orr & |"|<id>|"|
& restore what was ??!^[saved] as <id> earlier
\cr
&\orr & |{| <pos> <decor> |}|
& the $c$ resulting from interpreting the ??!^[group]
\cr
\noalign{\smallbreak}
%
??w![<vector>]
&\iss & ??c![0]
& zero
\cr
&\orr & |<| <dimen> |,| <dimen> |>|
& absolute??c[<>]
\cr
&\orr & |<| <dimen> |>|
& absolute with equal dimensions
\cr
&\orr & |(| <factor> |,| <factor> |)|
& in current ??!^[base]??c[()]
\cr
&\orr & ??c![a] |(| <number> |)|
& ??!^[angle in current base]
\cr
&\orr & <corner>
& from reference point to <corner> of $c$
\cr
&\orr & <corner> |(| <factor> |)|
& The <corner> multiplied with <factor>
\cr
&\orr & |/| <direction> <dimen> |/|
& vector <dimen> ??!^[in <direction>]??c[//]
\cr
\noalign{\smallbreak}
%
??w![<corner>]
&\iss & ??c![L]\orr??c![R]\orr??c![D]\orr??c![U]
& ??!^[offset] to left, right, down, up side
\cr
&\orr & ??c![CL]\orr??c![CR]\orr??c![CD]\orr??c![CU]\orr??c![C]
& ??!^[offset] to center of side, true center
\cr
&\orr & ??c![LD]\orr??c![RD]\orr??c![LU]\orr??c![RU]
& ??!^[offset] to actual left/down, \dots\ corner
\cr
&\orr & ??c![E]\orr??c![P]
& ??!^[offset] to nearest/proportional edge point to $p$
\cr
\noalign{\smallbreak}
%
??w![<place>]
&\iss & ??c![<] <place>
& ??!^[shave] ??c![(0)] to edge of $p$, $f \from |0|$
\cr
&\orr & ??c![>] <place>
& ??!^[shave] ??c![(1)] to edge of $c$, $f \from |1|$
\cr
&\orr & |(| <factor> |)| <place>
& $f \from <factor>$
\cr
&\orr & <slide>
& ??!^[pick place] and apply <slide>
\cr
\noalign{\smallbreak}
%
??w![<slide>]
&\iss & |/| <dimen> |/|
& ??!^[slide] <dimen> further along connection
\cr
&\orr & <empty>
& no slide
\cr
\noalign{\smallbreak}
%
??w![<stacking>]
&\iss & ??c![@i] \orr\ ??c![@(] \orr\ ??c![@)]
& init, enter, leave ??!^[stack]
\cr
&\orr & ??c![@+] <coord> \orr\ ??c![@-] <coord>
& push $<coord>$; $c\from<coord>$ and pop (on ??!^[stack])
\cr
&\orr & ??c![@@] <coord>
& do $<coord>$ ??!^[for every stack element]
\cr
\noalign{\smallbreak}
%
??w![<saving>]
&\iss & ??c![=] |"|<id>|"|
& ??!^[save] $c$ as |"|<id>|"|
\cr
&\orr & |=|<code> |"|<id>|"|
& ??!^[define macro] |"|<id>|"|
\cr
\end{syntax}
\unskip\vskip-1em
\caption{\protect<pos>itions.}??=[f.pos]
\vfill
\end{figure*}
All possible positions are shown in figure~??[f.pos] with explanatory
notes below.
\begin{exercise}
Which of the positions |0|, |<0pt,0pt>|, |<0pt>|, |(0,0)|, and
|/0pt/| is different from the others?
\answertext{In the default setup they are all denote the reference point of
the \XY-picture but the cartesian coordinate <pos> ??c![(0,0)]
denotes the point "origo" that may be changed to something else using
the |:| operator.}
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Parsing:}
First the ??c![\POS] and ??c![\afterPOS] <decor>ations, and similar
??c![\afterCOORD] and ??c![\afterVECTORorEMPTY] ones. They handle
parsing of <pos>, <coord>, and <vector>; parsing of <corner> and
<place> is presented along with note~??[corner] and~??[<place>]
explaining them.
\DOCMODE(
\xydef@\POS{\afterPOS{}}
\xydef@\afterPOS#1{%
\DN@##1{\def\afterPOS@{\def\afterPOS@{##1}#1}}%
\expandafter\next@\expandafter{\afterPOS@}%
\afterCOORD{\xyFN@\POS@}}
\xylet@\afterPOS@=\empty
\xydef@\afterCOORD#1{%
\DN@##1{\def\afterCOORD@{\def\afterCOORD@{##1}#1}}%
\expandafter\next@\expandafter{\afterCOORD@}%
\afterVECTORorEMPTY{\xy@@\czeroEdge@ \afterCOORD@}{\xyFN@\COORD@}}
\xylet@\afterCOORD@=\empty
\xydef@\afterVECTORorEMPTY#1#2{%
\DN@##1{\def\afterVECTOR@{\def\afterVECTOR@{##1}%
\ifVECTORempty@\DN@{#2}\else\DN@{#1}\fi \next@}}%
\expandafter\next@\expandafter{\afterVECTOR@}%
\xyFN@\VECTOR@}
\xynew@{if}\ifVECTORempty@
\xylet@\afterVECTOR@=\empty
\DOCMODE)
The ??c![\afterVECTORorEMPTY] command is special in that it takes two
arguments: the `continuation' if a <vector> was found and the
continuation if <empty> was found (this is not applicable to the
other two since <empty> is a legal <coord> and thus also a legal
<pos>).
Next we proceed with the actual parsing primitives: |\COORD@|,
|\POS@|, and |\VECTOR@|. These are bound to |\xyCOORD@|, |\xyPOS@|,
and |\xyVECTOR@| in order to be extendable, \eg, the |matrix| option
extends <coord> to support the |[|"row"|,| "column"|]| format by
redefining |\COORD@| to first test for this new format and then call
|\xyCOORD@|.
The parsing commands above are set up such that they all first call
the |\VECTOR@| command. <coord> and <pos> parsing then proceeds with
calling the |\COORD@| if there was no <vector>. <pos> parsing then
calls |\POS@| to continue the <pos> (in both cases).
First <vector>s:
\DOCMODE(
\xydef@\xyVECTOR@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\VECTOR@}%gobble spaces
\else \ifcat A\noexpand\next \let\next@=\VECTOR@letter
\else \let\next@=\VECTOR@other \fi\fi \next@}
\xylet@\VECTOR@=\xyVECTOR@
\DOCMODE)
All letters used for <vector>s are uppercase <corner>s except for |a|
used for angles (where the main code is in note~??[angle in current
base]):
\DOCMODE(
\xydef@\VECTOR@letter{%
\ifx a\next \expandafter\VECTOR@a \else \expandafter\CORNER@ \fi}
\xydef@\VECTOR@a a(#1){\xy@{a(#1)}{\vfromcartesianangle@{#1}}%
\VECTORempty@false \afterVECTOR@}
\DOCMODE)
The <corner> trick is to do nothing when there is nothing and
initialise both $X$ and $Y$ in all other cases.
\DOCMODE(
\xydef@\CORNER@{%
\xy@{}{\A@=-.5\Lc \advance\A@.5\Rc \B@=-.5\Dc \advance\B@.5\Uc
\let\nextii@=\zeroit@}%
\VECTORempty@true\CORNER@i}
\xydef@\zeroit@#1{#1=\z@}
\xydef@\CORNER@i{%
\ifx D\next \DN@ D{\xy@{D}{\Yc=-\Dc \nextii@\Xc \B@=\Yc}\CORNER@ii}%
\else\ifx U\next \DN@ U{\xy@{U}{\Yc= \Uc \nextii@\Xc \B@=\Yc}\CORNER@ii}%
\else\ifx L\next \DN@ L{\xy@{L}{\Xc=-\Lc \nextii@\Yc \A@=\Xc}\CORNER@ii}%
\else\ifx R\next \DN@ R{\xy@{R}{\Xc= \Rc \nextii@\Yc \A@=\Xc}\CORNER@ii}%
\else\ifx C\next \DN@ C{\xy@{C}{\Xc= \A@ \Yc= \B@}\CORNER@ii}%
\else\ifx E\next \DN@ E{\xy@{E}{%
\A@=\Xc \B@=\Yc \the\Edgec\z@ \advance\Xc-\A@ \advance\Yc-\B@}\CORNER@ii}%
\else\ifx P\next \DN@ P{\xy@{P}{%
\A@=\Xc \B@=\Yc \the\Edgec\thr@@ \advance\Xc-\A@ \advance\Yc-\B@}%
\CORNER@ii}%
\else\ifx (\next %)
\DN@(##1){\xy@{(##1)}{\Xc=##1\Xc \Yc=##1\Yc}\afterVECTOR@}%
\else \let\next@=\afterVECTOR@
\fi\fi\fi\fi\fi\fi\fi\fi \next@}
\xydef@\CORNER@ii{\xy@@{\let\nextii@=\eat@}%
\VECTORempty@false \xyFN@\CORNER@i}
\DOCMODE)
|\CORNER@i| recognises the |(|<factor>|)| also; this does no harm as
it was never called if the first character was a |(|.
The remaining <vector> forms just set $X$ and $Y$:
\DOCMODE(
\xydef@\VECTOR@other{%
\addLT@\ifx \next
\addGT@{\addLT@\DN@##1}{%
\xy@{<##1>}{\vfromabsolute@{##1}}\VECTORempty@false\afterVECTOR@}%
\else\ifx (\next %)
\DN@(##1){%
\xy@{(##1)}{\vfromcartesian@{##1}}\VECTORempty@false\afterVECTOR@}%
\else\ifx /\next %/
\DN@/##1/{\xy@{/##1/}{\vfromslide@{##1}}%
\VECTORempty@false\afterVECTOR@}%
\else\ifx 0\next
\DN@ 0{\xy@{0}{\Xc=\z@ \Yc=\z@}\VECTORempty@false\afterVECTOR@}%
\else
\DN@{\VECTORempty@true\afterVECTOR@}%
\fi\fi\fi\fi \next@}
\DOCMODE)
Next <coord>inates that are not <vector>s:
\DOCMODE(
\xydef@\xyCOORD@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\COORD@}%gobble spaces
\else \ifcat A\noexpand\next \let\next@=\xyCOORD@letter
\else \let\next@=\xyCOORD@other \fi\fi \next@}
\xylet@\COORD@=\xyCOORD@
\xydef@\xyCOORD@letter{%
\ifx c\next
\DN@ c{\xy@{c}{}\afterCOORD@}%
\else\ifx p\next
\DN@ p{\xy@{p}\cfromp@ \afterCOORD@}%
\else\ifx x\next
\DN@ x{\xy@{x}{\Rc=\Xxbase \Uc=\Yxbase \intersect@}\afterCOORD@}%
\else\ifx y\next
\DN@ y{\xy@{y}{\Rc=\Xybase \Uc=\Yybase \intersect@}\afterCOORD@}%
\else\ifx s\next
\DN@ s##1{\xy@{s{##1}}{\cfroms@{##1}}\afterCOORD@}%
\else \let\next@=\afterCOORD@ \fi\fi\fi\fi\fi \next@}
\xydef@\xyCOORD@other{%
\ifx "\next %"
\DN@"##1"{\xy@{"##1"}{\cfromid@{##1}}\afterCOORD@}%
\else\ifx \bgroup\next
\DN@##1{\xy@{{##1}}{\enter@{\pfromthep@\basefromthebase@}}%
\POS##1\relax \xy@@\leave@ \afterCOORD@}%
\else \let\next@=\afterCOORD@ \fi\fi \next@}
\DOCMODE)
Finally <pos> parsing after <coord> (possibly <vector>) is
interpreted:
\DOCMODE(
\xydef@\xyPOS@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\POS@}%gobble spaces
\else\addPLUS@\ifx \next
\addPLUS@\DN@{\xy@+{\enter@\cplusthec@}%
\afterCOORD{\xy@@\leave@ \xyFN@\POS@}}%
\else\addDASH@\ifx \next
\addDASH@\DN@{\xy@-{\enter@\cplusthec@}%
\afterCOORD{\xy@@{\Xc=-\Xc \Yc=-\Yc\leave@}\xyFN@\POS@}}%
\else\ifx !\next
\DN@ !{\xy@!{\enter@\cskewthec@}\afterCOORD{\xy@@\leave@ \xyFN@\POS@}}%
\else\addDOT@\ifx \next
\addDOT@\DN@{\xy@.{\enter@\cmergethec@}%
\afterCOORD{\xy@@\leave@ \xyFN@\POS@}}%
\else\ifx ,\next
\DN@ ,{\xy@,{}\afterCOORD{\xyFN@\POS@}}%
\else\ifx ;\next
\DN@ ;{\xy@;{\swap@}\afterCOORD{\xyFN@\POS@}}%
\else\ifx :\next
\DN@ :{\xyFN@\oneortwocolons@}%
\else\addEQ@\ifx \next
\addEQ@\DN@{\xyFN@\saveid@}%
\else\ifx *\next
\DN@ *{\xyFN@\oneortwostars@}%
\else \ifx ?\next
\DN@?{\xy@?{}\afterPLACE{\xyFN@\POS@}}%
\else \addAT@\ifx \next
\addAT@\DN@{\xyFN@\STACK@}%
\else
\let\next@=\afterPOS@
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@}
\xylet@\POS@=\xyPOS@
\DOCMODE)
The final functions serve only to distinguish between the single
character |:|/|*| and dual character |::|/|**| operators:
\DOCMODE(
\xydef@\oneortwocolons@{\DNii@{\afterCOORD{\xyFN@\POS@}}%
\ifx :\next \xy@{::}{\setbase@@\Xc\Yc}\DN@:{\nextii@}%
\else \xy@:{\setbase@\Xp\Yp\Xc\Yc}\let\next@=\nextii@ \fi
\next@}
\xydef@\oneortwostars@{%
\ifx *\next
\DN@*##1##{\nextii@{##1}}%
\DNii@##1##2{\xy@@ix@{{##1}{##2}}%
\xy@{**##1{##2}}{\expandafter\connect@\the\toks9}\xyFN@\POS@}%
\else
\DN@##1##{\nextii@{##1}}%
\DNii@##1##2{\xy@@ix@{{##1}{##2}}%
\xy@{*##1{##2}}{\expandafter\drop@\the\toks9}\xyFN@\POS@}%
\fi
\next@}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Simple actions:}
Next follow the simplest actions; the complicated ones are explained
along with their notes below.
\DOCMODE(
\xydef@\cfromp@{\Xc=\Xp \Yc=\Yp \Uc=\Up \Dc=\Dp \Lc=\Lp \Rc=\Rp
\Edgec=\expandafter{\the\Edgep}}
\xydef@\pfromc@{\Xp=\Xc \Yp=\Yc \Up=\Uc \Dp=\Dc \Lp=\Lc \Rp=\Rc
\Edgep=\expandafter{\the\Edgec}}
\xydef@\swapdimen@#1#2{\dimen@=#1\relax #1=#2\relax #2=\dimen@}
\xydef@\swap@{\swapdimen@\Xc\Xp \swapdimen@\Yc\Yp
\swapdimen@\Uc\Up \swapdimen@\Dc\Dp \swapdimen@\Lc\Lp \swapdimen@\Rc\Rp
\toks@=\Edgec \Edgec=\Edgep \Edgep=\toks@}
\DOCMODE)
Next the parsing of coordinate pairs in |<>|:
\DOCMODE(
\xydef@\vfromabsolute@#1{\vfromabsolute@@#1,@}
\xydef@\vfromabsolute@@#1,#2@{\Xc=#1\relax
\DN@{#2}\ifx\next@\empty \Yc=\Xc
\else \DN@##1,{\Yc=##1}\next@#2\relax \fi}
\DOCMODE)
The next group of commands are used to store on the control stack
with the |\enter@| command, so they "expand" to something useful:
\DOCMODE(
\xydef@\cfromthec@{\Xc=\the\Xc \Yc=\the\Yc
\Uc=\the\Uc \Dc=\the\Dc \Lc=\the\Lc \Rc=\the\Rc
\Edgec={\expandafter\noexpand\the\Edgec}}
\xydef@\cfromthep@{\Xc=\the\Xp \Yc=\the\Yp
\Uc=\the\Up \Dc=\the\Dp \Lc=\the\Lp \Rc=\the\Rp
\Edgec={\expandafter\noexpand\the\Edgep}}
\xydef@\pfromthep@{\Xp=\the\Xp \Yp=\the\Yp
\Up=\the\Up \Dp=\the\Dp \Lp=\the\Lp \Rp=\the\Rp
\Edgep={\expandafter\noexpand\the\Edgep}}
\xydef@\pfromthec@{\Xp=\the\Xc \Yp=\the\Yc
\Up=\the\Uc \Dp=\the\Dc \Lp=\the\Lc \Rp=\the\Rc
\Edgep={\expandafter\noexpand\the\Edgec}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{notes}
\note??=[arithmetic]
%
When doing arithmetic with |+| and |-| then the resulting object
inherits the size of the <coord>, \ie, the right argument---this will
be zero if the <coord> is a <vector>.
\begin{exercise}
How do you set $c$ to an object the same size as the saved object
|"ob"| but moved |<|$X$|,|$Y$|>|?
\answertext{Use the <pos>ition |<|$X$|,|$Y$|>+"ob"|.}
\end{exercise}
\DOCMODE(
\xydef@\cplusthec@{\advance\Xc\the\Xc \advance\Yc\the\Yc}
\DOCMODE)
\note??=[skew]
%
"Skewing" using |!| just means that the reference point of $c$ is
moved with as little change to the shape of the object as possible,
\ie, the edge of~$c$ will remain in the same location except that it
will grow larger to avoid moving the reference point outside~$c$.
%
\begin{exercise}
What does the <pos> \dots|!R-L| do?
\answertext{It first sets $c$ according to ``\dots''. Then it changes $c$ to
the point right of $c$ at the same distance from the right edge of
$c$ as its width, $w$, \ie,
$$
\xy
*+\hbox{The \dots}="it" *\frm{_\}}!D-U*{w}
,{"it"+RD}.{"it"+RU}.{"it"!R-L*{\times}+0}!C *\frm{_\}}!D-U*{w}
\endxy
$$}
\end{exercise}
%
\BUG: The result of |!| is always a rectangle currently.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Procedure:}
|!| moves the center of $c$ by a temporarily read $c'$ and then
readjusts the extents:
$$
\begin{array}{rclcl}
D_c &:=& Y'+Y_c - \min(Y'-D', Y'+Y_c) &=& \max(Y_c+D',0)\\
U_c &:=& \max(Y'+U', Y'+Y_c) - (Y'+Y_c) &=& \max(U'-Y_c,0)\\
Y_c &:=& Y'+Y_c\\
L_c &:=& X'+X_c - \min(X'-L', X'+X_c) &=& \max(X_c+L',0)\\
R_c &:=& \max(X'+R', X'+X_c) - (X'+X_c) &=& \max(R'-X_c,0)\\
X_c &:=& X'+X_c\\
\end{array}
$$
\DOCMODE(
\xydef@\cskewthec@{%
\noexpand\cskew@{\the\Yc}{\the\Xc}{\the\Dc}{\the\Uc}{\the\Lc}{\the\Rc}}
\xydef@\cskew@#1#2#3#4#5#6{%
\Dc=#3\advance\Dc \Yc \ifdim\Dc<\z@ \Dc=\z@ \fi
\Uc=#4\advance\Uc-\Yc \ifdim\Uc<\z@ \Uc=\z@ \fi
\advance\Yc#1%
\Lc=#5\advance\Lc \Xc \ifdim\Lc<\z@ \Lc=\z@ \fi
\Rc=#6\advance\Rc-\Xc \ifdim\Rc<\z@ \Rc=\z@ \fi
\advance\Xc#2%
\Edgec={\rectangleEdge}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[covering]
%
A <pos> "covers" another if it is a rectangle with size sufficiently
large that the other is ``underneath''. The |.| operation
``extends'' a <pos> to cover an additional one---the reference point
of $c$ is not moved but the shape is changed to a rectangle such that
the entire $p$ object is covered.
\NOTE: non-rectangular objects are first ``translated'' into a
rectangle by using a diagonal through the object as the diagonal of
the rectangle.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Procedure:}
|.| takes a temporary object $c'$ and adjusts the extents of $c$ such
that it is covered.
$$
\begin{array}{rclcl}
L_c &:=& X' - \min(X'-L_c, X-L) &=& \max(L_c, A+L)\\
R_c &:=& \max(X'+R_c, X+R) - X' &=& \max(R_c, -A+R)\\
D_c &:=& Y' - \min(Y'-D_c, Y-D) &=& \max(D_c, B+D)\\
U_c &:=& \max(Y'+U_c, Y+U) - Y' &=& \max(U_c, -B+U)\\
\end{array}
$$
with $|<|A|,|B|>| = |<|X'-X|,|Y'-Y|>|$. First method~2 of the object
is used to convert it into a rectangle.
\DOCMODE(
\xydef@\cmergethec@{%
\noexpand\cmerge@{\the\Yc}{\the\Xc}{\the\Dc}{\the\Uc}{\the\Lc}{\the\Rc}}
\xydef@\cmerge@#1#2#3#4#5#6{\the\Edgec4%
\A@=#2\advance\A@-\Xc \B@=#1\advance\B@-\Yc
\dimen@=#5\advance\Lc \A@ \ifdim\Lc<\dimen@ \Lc=\dimen@ \fi
\dimen@=#6\advance\Rc-\A@ \ifdim\Rc<\dimen@ \Rc=\dimen@ \fi
\dimen@=#3\advance\Dc \B@ \ifdim\Dc<\dimen@ \Dc=\dimen@ \fi
\dimen@=#4\advance\Uc-\B@ \ifdim\Uc<\dimen@ \Uc=\dimen@ \fi
\advance\Xc\A@ \advance\Yc\B@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[base]
%
The operations |:| and |::| set the "base" used for <coord>inates on
the form $|(|x|,|y|)|$. The |:| operation will set
|<|$X_"origin"$|,| $Y_"origin"$|>| to~$p$, |<|$X_"xbase"$|,|
$Y_"xbase"$|>| to $c-"origin"$, and~|<|$X_"ybase"$|,| $Y_"ybase"$|>|
to |<|${-}Y_"xbase"$|,| $X_"xbase"$|>| (this ensures that it is a
usual square coordinate system). The |::| operation may then be used
afterwards to make nonsqare bases by just setting "ybase" to
$c-"origin"$. Here are two examples |0;<1cm,0cm>:| will set the
coordinate system
$$
\xy
<0cm,0cm>*\dir{o};<1cm,0cm>:
(0,0);{(1,0)**\dir{-}?>*\dir{>}},{(0,1)**\dir{-}?>*\dir{>}},
(0,0)*+!UR\hbox{\small"origin"},
(1,0)*+!LC\hbox{\small"xbase"},
(0,1)*!D\hbox{\small"ybase"},
(1,1)*{*}*++!CL{|(1,1)|}+0;(0,1)**\dir{.},(1,0)**\dir{.}
\endxy
$$
and |<1cm,.5cm>;| |<2cm,1.5cm>:| |<1cm,1cm>::| will define
$$
\xy
<0cm,0cm>*\dir{o}, <1cm,.5cm>;<2cm,1.5cm>:
%
(0,0);{(0,1)**\dir{--}?(1)*\dir{>}},
(0,1)*+!R\txt\small{"ybase"\\before\\{\tt::}},
%
<1cm,1cm>::
(0,0);{(1,0)**\dir{-}?(1)*\dir{>}},{(0,1)**\dir{-}?(1)*\dir{>}},
(0,0)*+!LU\txt\small{"origin"},
(1,0)*+!LC\txt\small{"xbase"},
(0,1)*!D\txt\small{"ybase"},
(1,1)*{*}*++!CL{|(1,1)|}+0;(0,1)**\dir{.},(1,0)**\dir{.}
\endxy
$$
where in each case the $\circ$ is at |0|, the base vectors have been
drawn, and the $\times$ is at |(1,1)|.
When working with vectors these two special <factor>s are
particularly useful:
%
\begin{defs}
|\halfroottwo| & $0.70710678\approx\sqrt2/2$ \cr
|\halfrootthree| & $0.86602540\approx\sqrt3/2$ \cr
\end{defs}
\DOCMODE(
\xydef@\halfroottwo{.70710678}
\xydef@\halfrootthree{.8660254}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Procedure:}
The code chosen by the parsing is very simple; the only tricky bit is
to ensure that |\basefromthebase@| always expands to set the current
base.
\DOCMODE(
\xydef@\vfromcartesian@#1{\vfromcartesian@@#1@}
\xydef@\vfromcartesian@@#1,#2@{%
\Xc=\Xorigin \advance\Xc#1\Xxbase \advance\Xc#2\Xybase
\Yc=\Yorigin \advance\Yc#1\Yxbase \advance\Yc#2\Yybase}
\xydef@\setbase@#1#2#3#4{%
\Xorigin=#1\relax \Yorigin=#2\relax
\Xxbase=#3\relax \advance\Xxbase-\Xorigin
\Yxbase=#4\relax \advance\Yxbase-\Yorigin
\Xybase=-\Yxbase \Yybase=\Xxbase}
\xydef@\setbase@@#1#2{%
\Xybase=#1\relax \advance\Xybase-\Xorigin
\Yybase=#2\relax \advance\Yybase-\Yorigin}
\xydef@\basefromthebase@{\Xorigin=\the\Xorigin \Yorigin=\the\Yorigin
\Xxbase=\the\Xxbase \Yxbase=\the\Yxbase
\Xybase=\the\Xybase \Yybase=\the\Yybase}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[angle in current base]
%
An "angle" $\alpha$ in \Xy-pic is the same as the coordinate pair
$|(|\cos\alpha|,|\sin\alpha|)|$ where $\alpha$ must be an integer
interpreted as a number of degrees. Thus the <vector> |a(0)| is the
same as |(1,0)| and |a(90)| as |(0,1)|, etc.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The translation involves several steps: (??_[ang1])~Normalise the
argument to be within $[0^\circ:360^\circ[$. (??_[ang2])~Flip angle
around $x$-axis and then $y$-axis to ensure it is in the first
quadrant, \ie, within $[0^\circ:90^\circ[$. (??_[ang3])~Flip around
diagonal to ensure angle within $[0^\circ:45^\circ[$.
(??_[ang4])~Find values $\phi\le\alpha\lt\psi$ from the table in
figure~??[f.angles] (using recursive table lookup -- at most 3 tests
needed). (??_[ang5])~build vector $(x,y)$ interpolated between the
sin/cos values for $\phi$ and $\psi$ using the formula
$$
\left(\cos\phi + k(\cos\psi-\cos\phi) ,
\sin\phi + k(\sin\psi-\sin\phi) \right) ~,
\quad\hbox{where}~k = \frac{\alpha-\phi}{\psi-\phi}
$$
(??_[angx])~build the chosen vector.
\begin{figure}
\noindent Vectors for angles in $[0^\circ:45^\circ]$: contains all
angles required to typeset fractions up to $\frac{n}{12}\times2\pi$,
$\frac1{16}\times2\pi$, and $\frac1{24}\times2\pi$ exactly, and two
extra low ones to ensure that all gaps are less than $5^\circ$ and
the precision of all sine/cosines better than $\frac1{1000}$.
$$
\small
\def"{\vphantom{\frac()}\frac}
\begin{array}{\otherbar l\otherbar r@{~}l\otherbar c\otherbar c\otherbar}
\hline
~\alpha & (\cos\alpha, & \sin\alpha) & \hbox{fractions of $2\pi$} &
\hbox{flipped fractions of $2\pi$} \\
\hline
~0&(1,&0) & "0{n}
& "12,"14,"24,"28,"34,"36,"3{12},"48,"5{10},"68,"6{12},"9{12} \\
~4.090909 & (.99677570, & .08023846) & - & - \\
~6 & (.99452190, & .10452846) & - & - \\
~8.181818 & (.98982144, & .14231484) & "3{11} & "8{11} \\
10 & (.98480775, & .17364818) & "79 & "29 \\
12.857143 & (.97492791, & .22252093) & "27 & "57 \\
15 & (.96592583, & .25881905) & "1{24} & \\
16.363636 & (.95949297, & .28173256) & "6{11} & "5{11} \\
18 & (.95105652, & .30901699) & "3{10},"45,"8{10} & "15,"2{10},"7{10} \\
20 & (.93969262, & .34202014) & "59 & "49 \\
22.5 & (.92387953, & .38268343) & "1{16} & \\
24.545455 & (.90963200, & .41541501) & "9{11} & "2{11} \\
25.714286 & (.90096887, & .43388374) & "47 & "37 \\
30 & (.86602540, & .5) & "13,"1{12},"26,"39,"4{12},"56,"7{12},"{10}{12}
& "16,"23,"2{12},"46,"5{12},"69,"8{12},"{11}{12} \\
32.727273 & (.84125353, & .54064082) & "1{11} & "{10}{11} \\
36 & (.80901699, & .58778525) & "1{10},"35,"6{10} & "25,"4{10},"9{10} \\
38.571429 & (.78183148, & .62348980) & "67 & "17 \\
40 & (.76604444, & .64278761) & "19 & "89 \\
40.909091 & (.75574957, & .65486073) & "4{11} & "7{11} \\
45 & (.70710678, & .70710678) & "18,"38,"58,"78 & - \\
\hline
\end{array}
$$
\caption{Computing angle vectors}
??=[f.angles]
\end{figure}
\DOCMODE(
\xydef@\vfromcartesianangle@#1{\enter@\basefromthebase@ \R@=#1\p@
\B@=360\p@ %?*[ang1]
\loop@ \ifdim\R@<\z@ \advance\R@\B@ \repeat@
\loop@ \ifdim\R@>\B@ \advance\R@-\B@ \repeat@
\ifdim\R@<.5\B@\else \R@=-\R@ \advance\R@\B@ %?*[ang2]
\Xybase=-\Xybase \Yybase=-\Yybase \fi
\B@=180\p@
\ifdim\R@<.5\B@\else \R@=-\R@ \advance\R@\B@
\Xxbase=-\Xxbase \Yxbase=-\Yxbase \fi
\B@=90\p@ %?*[ang3]
\ifdim\R@<.5\B@ \let\nextiii@=\literal@
\else \R@=-\R@ \advance\R@\B@ \def\nextiii@##1,##2@{##2,##1@}\fi
\dimen@=\z@ \DN@{1,0@}% %?*[ang4]
\dimen@ii=45\p@ \DNii@{.70710678,.70710678@}%
\chooseangleinterval@
{\chooseangleinterval@
{\chooseangleinterval@
{\chooseangleinterval@
{\chooseangleinterval@
{}%
{4.090909}{.99677570,.08023846@}%
{}}%
{6}{.99677570,.08023846@}%
{\chooseangleinterval@
{}%
{8.181818}{.98982144,.14231484@}%
{}}}%
{10}{.98480775,.17364818@}%
{\chooseangleinterval@
{}%
{12.857143}{.97492791,.22252093@}%
{}}}%
{15}{.96592583,.25881905@}%
{\chooseangleinterval@
{\chooseangleinterval@
{}%
{16.363636}{.95949297,.28173256@}%
{}}%
{18}{.95105652,.30901699@}%
{\chooseangleinterval@
{}%
{20}{.93969262,.34202014@}%
{}}}}%
{22.5}{.92387953,.38268343@}%
{\chooseangleinterval@
{\chooseangleinterval@
{\chooseangleinterval@
{}%
{24.545455}{.90963200,.41541501@}%
{}}%
{25.714286}{.90096887,.43388374@}%
{}}%
{30}{.86602540,.5@}%
{\chooseangleinterval@
{\chooseangleinterval@
{}%
{32.727273}{.84125353,.54064082@}%
{}}%
{36}{.80901699,.58778525@}%
{\chooseangleinterval@
{\chooseangleinterval@
{}%
{38.571429}{.78183148,.62348980@}%
{}}%
{40.909091}{.75574957,.65486073@}%
{\chooseangleinterval@
{}%
{40}{.76604444,.64278761@}%
{}}}}}%
\A@=\R@ \advance\A@-\dimen@ %?*[ang5]
\ifdim\ifdim\A@<\z@-\fi\A@<.01\p@ \edef\next@{\expandafter\nextiii@\next@}%
\else \B@=\dimen@ii \advance\B@-\R@
\ifdim\A@<\B@ \dimen@=\toradians@\A@
\edef\next@{\next@ \expandafter\removePT@\the\dimen@ @}%
\else \dimen@=-\toradians@\B@
\edef\next@{\nextii@ \expandafter\removePT@\the\dimen@ @}%
\fi
\expandafter\interpolatepoint@\next@
\edef\next@{\expandafter\nextiii@\next@}%
\fi
\expandafter\vfromcartesian@@\next@ %?*[angx]
\leave@}
\xydef@\chooseangleinterval@#1#2#3#4{%
\B@=#2\p@ \def\next{#3}%
\ifdim\R@<\B@ \dimen@ii=\B@ \let\nextii@=\next #1%
\else \dimen@=\B@ \let\next@=\next \ifdim\B@<\R@ #4\fi\fi}
\xydef@\interpolateinterval@#1,#2@#3,#4@{%
\A@=#1\p@ \dimen@=#3\p@ \advance\dimen@-\A@ \advance\A@\next\dimen@
\B@=#2\p@ \dimen@=#4\p@ \advance\dimen@-\B@ \advance\B@\next\dimen@
\edef\next@{\expandafter\removePT@\the\A@,\expandafter\removePT@\the\B@ @}}
\xydef@\toradians@{0.01745329}
\xydef@\interpolatepoint@#1,#2@#3@{%
\A@=#1\p@ \dimen@ii=#3\A@ \dimen@ii=-.5\dimen@ii \advance\A@#3\dimen@ii
\dimen@=-#2\p@ \advance\A@#3\dimen@
\B@=#2\p@ \dimen@ii=#3\B@ \dimen@ii=-.5\dimen@ii \advance\B@#3\dimen@ii
\dimen@=#1\p@ \advance\B@#3\dimen@
\edef\next@{\expandafter\removePT@\the\A@,\expandafter\removePT@\the\B@ @}}
\DOCMODE)
Here is a test of all the directions:
$$
\def\a(#1){\save"o";a(#1)**\dir{-}*+__!P{\scriptscriptstyle#1}\restore}
\def\ad(#1){\save"o",a(#1)*{\cdot}\restore}
%
\newcount\n \newcount\m
\xy (50,0):0*[o]\cir<4pt>{}="o"\relax
\n=0 %
\loop \expandafter\a\expandafter(\the\n)%
\m=\n
\advance\m1 \expandafter\ad\expandafter(\the\m)%
\advance\m1 \expandafter\ad\expandafter(\the\m)%
\advance\m1 \expandafter\ad\expandafter(\the\m)%
\advance\m1 \expandafter\ad\expandafter(\the\m)%
\advance\n5 \ifnum361>\n\relax \repeat
\endxy
$$
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[drop]
%
To "drop" an <object> at $c$ with |*| means to actually physically
typeset it in the picture with reference position at $c$---how this
is done depends on the <object> in question and is described in
detail in~\S??[object]. The intuition with a drop is to do something
that typesets something a $|<|X_c|,|Y_c|>|$ and sets the edge of $c$
accordingly.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subparagraph*{Procedure:}
(??_[drop1])~sets up the direction to allow for directionals and
builds the requested <object> in the (global) |\lastobjectbox@| box,
(??_[drop2])~adjust the picture size unless it is a hidden object,
setting $|\dimen@| = X_c-L_c$, and (??_[drop3])~drop the object in the
picture at the right point by setting |box0| and using the |\Drop@@|
method.
\DOCMODE(
\xydef@\drop@#1#2{% %?*[drop1]
\global\setbox\lastobjectbox@=\object#1{#2}%
\ifHidden@ \dimen@=\Xc \advance\dimen@-\Lc \else %?*[drop2]
\dimen@=\Yc \advance\dimen@ \Uc \ifdim\Ymax<\dimen@ \Ymax=\dimen@ \fi
\dimen@=\Yc \advance\dimen@-\Dc \ifdim\dimen@<\Ymin \Ymin=\dimen@ \fi
\dimen@=\Xc \advance\dimen@ \Rc \ifdim\Xmax<\dimen@ \Xmax=\dimen@ \fi
\dimen@=\Xc \advance\dimen@-\Lc \ifdim\dimen@<\Xmin \Xmin=\dimen@ \fi \fi
\ifInvisible@\else %?*[drop3]
\setboxz@h{\kern\dimen@ \raise\Yc\box\lastobjectbox@}%
\ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ {\Drop@@}\fi}
\DOCMODE)
\NOTE: All typesetting into a picture should use or emulate |\drop@|!
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[connect]
%
The "connect" operation |**| will first compute a number of internal
parameters describing the direction from~$p$ to~$c$ and then typesets
a connection filled with copies of the <object> as illustrated
in~\S??[basics.connect]. The exact details of the connection depend
on the actual <object> and are described in general in~\S??[object].
The intuition with a connection is that it is something that typesets
something connecting $p$ and $c$ sets the |?| <pos> operator up
accordingly.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subparagraph*{Procedure:}
Set up the direction to allow for directional objects, then save
$c$, build the <object> in |\lastobjectbox@|, restore $c$, and perform
the |\Connect@@| method to connect using |\lastobjectbox@|.
\DOCMODE(
\xydef@\connect@#1#2{\setupDirection@ \enter@{\cfromthec@}%
\global\setbox\lastobjectbox@=\object#1{#2}\leave@
\Connect@@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[shave]??=[pick place]??=[slide]??=[<place>]
%
Using |?| will ``pick a place'' along the most recent connection
typeset with |**|. What exactly this means is determined by the
object that was used for the connection and by the modifiers
described in general terms here.
The ``shave'' modifiers in a <place>, |<| and |>|, change the default
<factor>, $f$, and how it is used, by `moving' the positions that
correspond to |(0)| and |(1)| (respectively): These are initially set
equal to~$p$ and~$c$, but shaving will move them to the point on the
edge of $p$ and $c$ where the connection ``leaves/enters'' them, and
change the default $f$ as indicated. When one end has already been
shaved thus then subsequent shaves will correspond to sliding the
appropriate position(s) a \TeX\ ??c![\jot] (usually equal to |3pt|)
further towards the other end of the connection (and past it).
Finally the "pick" action will pick the position located the fraction
$f$ of the way from |(0)| to |(1)| where $f=|0.5|$ if it was not set
(by |<|, |>|, or explicitly).
Finally, the <slide> will move the position a dimension further along
the connection at the picked position. For straight connections (the
only ones kernel \XY-pic provides) this is the same as adding a
vector in the tangent direction, \ie, $|?|\dots|/|A|/|$ is the same
as $|?|\dots|+/|A|/|$.
All this is probably best illustrated with some examples: each
$\otimes$ in figure~??[f.places] is typeset by a sequence of the form
$p$|;| $c$ |**\dir{.}| |?|<place> |*{\oplus}| where we indicate the
|?|<place> in each case.
\begin{figure*}[tp]
$$
%
\def\[#1]#2{\def\2{#2}%
\POS "p";"c"**{}
#2*+=[o]{\oplus}="x"*=<5em,3em>{}-#1*!#1\hbox{{\tt\codeof\2}};
"x"**\dir{-}?>*\dir{>}\ignorespaces}%
%
\xy
<0pt,110pt>*[o]=<20pt>{}="p"*\frm{oo}+L*!RC\hbox{$p$ is circular:~},
<270pt,0pt>*=<4em>\txt<4em>{$c$ is a square text!}="c",{\shaded\framed},
"p";"c"**\dir{--}\relax
%
\[UR]{?(0)}
\[UR]{?(1)}
\[UR]{?}
\[UR]{?(.7)}
%
\[D]{?<>(.5)}
\[DL]{?<>(.2)(.5)}
\[DL]{?<}
\[UR]{?<<<}
\[UR]{?<<</1cm/}
\[D]{?<(0)}
\[DL]{?>}
\[D]{?>>>>}
%
\[DL]{?<>(.7)}
\[D]{?>(.7)}
\endxy
$$
\caption{Example \protect<place>s}??=[f.places]
\end{figure*}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Procedure:}
The code for parsing <place> is the following. To get first |<>| to
move to edge and the remaining to move a |\jot| we have both initial
and continuing versions for each, the idea being that the second and
following go to the edge of a small temporary object with radius
|\jot|.
\NOTE: This parser tests the "new parsing principle" that |\xy@|
should always be called as |\xy@{| "source" |}{| "target" |}|!
\DOCMODE(
\xydef@\afterPLACE#1{%
\DN@##1{\def\afterPLACE@{\xy@@\leave@ \def\afterPLACE@{##1}#1}}%
\expandafter\next@\expandafter{\afterPLACE@}%
\xy@@{\enter@{\pfromthep@}%
\Creset@@
\def\PLACEf@{{.5}}%
\let\PLACEedgep@@=\PLACEedgep@ \let\PLACEedgec@@=\PLACEedgec@}%
\xyFN@\PLACE@}
\xydef@\PLACEf@{}
\xydef@\PLACEedgep@@{}
\xydef@\PLACEedgec@@{}
\xydef@\PLACEedgep@{\Cshavep@@ \def\PLACEedgep@@{\Cslidep@@\jot}}
\xydef@\PLACEedgec@{\Cshavec@@ \def\PLACEedgec@@{\Cslidec@@{-\jot}}}
\xylet@\afterPLACE@=\empty
\xydef@\PLACE@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\PLACE@}%gobble spaces
\else\addLT@\ifx \next
\addLT@\DN@{\addLT@\xy@{\def\PLACEf@{{0}}\PLACEedgep@@}\xyFN@\PLACE@}%
\else\addGT@\ifx \next
\addGT@\DN@{\addGT@\xy@{\def\PLACEf@{{1}}\PLACEedgec@@}\xyFN@\PLACE@}%
\else\ifx (\next %)
\DN@(##1){\def\PLACEf@{{##1}}\xy@{(##1)}{\def\PLACEf@{{##1}}}\xyFN@\PLACE@}%
\else
\DN@{\xy@@{\expandafter\Calong@@\PLACEf@ \czeroEdge@}\PLACE@@}%
\fi\fi\fi\fi \next@}
\xydef@\PLACE@@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\PLACE@@}%gobble spaces
\else\ifx /\next \DN@/##1/{\xy@{/##1/}{\Cslidec@@{##1}}\afterPLACE@}%
\else \let\next@=\afterPLACE@
\fi\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[axis intersection]
%
The positions denoted by the "axis intersection"
<coord>inates~??c![x] and~??c![y] are the points where the line
through $p$ and $c$ intersects with each axis. These are probably
best illustrated by the following example where they are shown for a
coordinate system and a $p,c$ pair:
$$
\xy;<1cm,.5cm>:<-.5cm,.5cm>::
(0,0)*+!UR{"origin"};
(1,0)*+!DR{"xbase"}**\dir{-}?>*\dir{>},
(0,0);(0,1)*+!DR{"ybase"}**\dir{-}?>*\dir{>},
(0.5,-1)="p"*\dir{o}*!LU\hbox{~$p$};
p+<.25cm,.5cm>="c"*\dir{o}*!LU\hbox{~$c$}*{}?(1),
%
"p";"c",x*+!LD{|x|}*\dir{*}*{}**\dir{.};(1,0)**\dir{.},
"p";"c",y*!U{\strut|y|}*\dir{*}*{}**\dir{.};(0,0)**\dir{.},
\endxy
$$
\begin{exercise}
%
Given predefined points $A$, $B$, $C$, and $D$ (stored as objects
|"A"|, |"B"|, |"C"|, and |"D"|), write a <coord> specification that
will return the point where the lines $\overline{AB}$ and
$\overline{CD}$ cross as the point marked with a large circle here:
%
\begin{code}
\xy
%
% set up and mark A, B, C, and D:
(0,0)="A" *\cir<1pt>{}*+!DR{A},
(7,10)="B" *\cir<1pt>{}*+!DR{B},
(13,8)="C" *\cir<1pt>{}*+!DL{C},
(15,4)="D" *\cir<1pt>{}*+!DL{D},
%
% goto intersection and name+circle it:
{"A";"B":"C";"D",x} ="I" *\cir<3pt>{},
%
% make dotted lines:
"I";"A"**{} +/1pc/;-/1pc/ **\dir{..},
"I";"D"**{} +/1pc/;-/1pc/ **\dir{..}
%
\endxy
\end{code}
$$\docode$$
%
\answertext{The <coord> ``|{"A";"B":| |"C";"D",| |x}|'' returns the cross
point. Here is how the author typeset the diagram in the exercise:}
\answercode
\answertext\displaycode
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Procedure:}
We solve the following equation in $a,b$:
$$
"origin" + a*|<|R_c|,|U_c|>| = c - b*(c-p)
$$
and then set
$$
|<|X_c|,|Y_c|>| := |<|X_c|,|Y_c|>| - b*(c-p)
\quad\text{with zero size}\quad
D_c,U_c,L_c,R_c := 0,0,0,0.
$$
The code uses $c=(X_c,Y_c,D_c,U_c,L_c,R_c)$ and $A,B$ as temporaries
and computes:
$$
\begin{array}{rcl}
|<|dX|,|dY|>| &:=& |<|X_c|,|Y_c|>| - |<|X_p,Y_p|>| \\[1pt]
|<|A|,|B|>| &:=& |<|X_c|,|Y_c|>| - |<|X_"origin"|,|Y_"origin"|>| \\[1pt]
|<|D_c|,|L_c|>| &:=& |<| \Det{R& dX\\U&dY} |,|
\Det{R&A\\U&B} |>| \\[1pt]
|<|X_c|,|Y_c|>| &:=& |<|X_c|,|Y_c|>| - (L_c/D_c)*|<|dX|,|dY|>|
\end{array}
$$
where we really do $D := (R/|pt|)dY - (U/|pt|)dX$ and similarly for
$L$.
\DOCMODE(
\xydef@\intersect@{%
\dX=\Xc \advance\dX-\Xp \dY=\Yc \advance\dY-\Yp
\A@=\Xc \advance\A@-\Xorigin \B@=\Yc \advance\B@-\Yorigin
\edef\next@{\expandafter\removePT@\the\Rc}%
\edef\nextii@{\expandafter\removePT@\the\Uc}%
\Dc=\next@\dY \advance\Dc-\nextii@\dX \divide\Dc\KK@
\Lc=\next@\B@ \advance\Lc-\nextii@\A@ \divide\Lc\KK@
\ifdim\Dc=\z@\DN@{0}\else \quotient@\next@\Lc\Dc \fi
\advance\Xc-\next@\dX \advance\Yc-\next@\dY
\czeroEdge@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[group]
%
A <pos> <decor> "grouped" in |{}|-braces is interpreted in a local
scope in the sense that any $p$ and "base" built within it are
forgotten afterwards. \REMARK: Only $p$ and "base" are restored---it
is not a \TeX\ group.
\begin{exercise}
What is the effect of the <coord>inate ``|{;}|''?
\answertext{To copy the $p$ value to $c$, \ie, equivalent to ``??c![p]''.}
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The code is inside |\POS@|.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[in <direction>]
%
The vector $|/|Z|/|$, where $Z$ is a <dimen>sion, is the same as the
vector $|<|Z\cos\alpha|,|Z\sin\alpha|>|$ where $\alpha$ is the angle
of the last direction set by a connection (|**|) or subsequent
placement (|?|) position.
\DOCMODE(
\xydef@\vfromslide@#1{\enter@\DirectionfromtheDirection@ \begingroup
\plainxy@\afterDIRECTIONorEMPTY\vfromslide@i\vfromslide@i#1@}
\xydef@\vfromslide@i#1@{%
\edef\next{\endgroup
\dimen@=#1\relax \Xc=\cosDirection\dimen@ \Yc=\sinDirection\dimen@}\next
\leave@}
\DOCMODE)
It is possible to give a <direction> as described in the next
section (figure~??[f.object] and note~??[<direction>] in
particular) that will then be used to set the value of
$\alpha$.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[offset]??=[corner]
%
A <corner> is an offset from the current $|<|X_c|,|Y_c|>|$ position
to a specific position on the edge of the $c$ object (the two-letter
ones may be given in any combination):
$$
\def\[#1]{\POS"box"+#1="x";"box"
**{} ?</-2em/*+\hbox{\tt#1};"x",**\dir{-}?>*\dir{>}}
%
\xy.(-5,-4).(15,9)*\frm{-}="box"*{c}="c";
"box"+L**\dir{.}, "box"+R**\dir{.}, "box"+D**\dir{.}, "box"+U**\dir{.}
%
\[L] \[R] \[D] \[U]
\[LD]\[RD]\[LU]\[RU]
\[CL]\[CR]\[DC]\[UC] \[C] \[P]
\POS"box"+(-20,-7)*{p}="p";"c"**\dir{--},"box"**{}\[E]
\endxy
$$
The `proportional' point |P| is computed in a complex way to make the
object look as much `away from $p$' as possible.
Finally, a following $|(|f|)|$ suffix will multiply the offset vector
by the <factor> $f$.
\begin{exercise}
What is the difference between the <pos>itions |c?<| and |c+E|?
\answertext{When using the kernel connections that are all straight there is
no difference, \eg, |**{}?<| and |**{}+E| denote exactly the same
position. However, for other connections it is not necessarily the
case that the point where the connection enters the current object,
denoted by |?<|, and the point where the straight line from $p$
enters the object, denoted by |+E|, coincide.}
\end{exercise}
\begin{exercise}
\begin{code}
\xy *=<3cm,1cm>\txt{Box}*\frm{-}
!U!R(.5) *\frm{..}*{\bullet} \endxy
\end{code}
%
What does
%
\displaycode
\noindent
typeset? "Hint": |\frm| is defined by the frame extension and just
typesets a frame of the kind indicated by the argument.
%
\answercode
\answertext{The code typesets the picture $$\docode$$}
\end{exercise}
\BUG: Currently only the single-letter corners (??c![L], ??c![R],
??c![D], ??c![U], ??c![C], ??c![E], and ??c![P]) will work for any
shape---the others silently assume that the shape is rectangular.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[stack]
%
The "stack" is a special construction useful for storing a sequence
of <pos>itions. |@i|~initialises, \ie, clears the stack such that it
contains no positions, |@+| `??w![push]es' $c$ onto it, \ie, adds on
the `top' of the stack, increasing the `depth' by one, and
|@-|~`??w![pop]s' the top element off the stack, decreasing the depth
by one. It is an error to pop when the stack is empty.
The special <coord>inates~|s|$n$, where $n$~is either a single digit
or a positive integer in |{}|s, refer to the $n$'th position "below
the top", \ie, |s0| is the position on the top, |s1| the one below
that, etc.
\begin{exercise}
Assume the positions $A$, $B$, $C$, and $D$ are defined.
What does the stack contain after the <pos>ition |@i,| $A$|@+,|
$B$|@+,| |@-,| $C$|,| $D$|@+|~?
\answertext{|s0| contains $D$ and |s1| contains~$A$.}
\end{exercise}
Furthermore, |@(| `hides' the current stack and creates a fresh stack
that can be used as above and once it has served its purpose |@)|
will purge it and reestablish the saved stack (issuing a warning
message if the purged stack is non-empty).
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
First the stack top and bottom, both initially~$-1$:
\DOCMODE(
\xydef@\sbot@{-1}
\xydef@\stop@{-1}
\DOCMODE)
Next the function to set $c\from|s|n$: only valid when $"bot" \lt
n+"bot" \lt "top"$.
\DOCMODE(
\xydef@\cfroms@#1{%
\count@=\stop@ \advance\count@-#1\relax
\DN@{\count@=\stop@ \advance\count@-\sbot@
\xyerror@{stack index out of range (should be 0..\the\count@)}{}}%
\ifnum\count@>\sbot@ \ifnum\count@>\stop@\else \let\next@=\relax \fi\fi
\csname S@\the\count@\endcsname}
\DOCMODE)
Finally the actual code to do the stack operations: it depends on the
`code' passed after |@|; spaces are not allowed:
\DOCMODE(
\xydef@\STACK@{%
\addPLUS@\ifx\next
\addPLUS@\DN@{\xy@{@+}{}\afterCOORD{\xy@@\spushc@ \xyFN@\POS@}}%
\else\addDASH@\ifx\next
\addDASH@\DN@{\xy@{@-}{}\afterCOORD{\xy@@\spop@ \xyFN@\POS@}}%
\else \ifx i\next \DN@ i{\xy@{@i}\sinit@ \xyFN@\POS@}%
\else \ifx (\next \DN@ ({\xy@{@(}\senter@ \xyFN@\POS@}%
\else \ifx )\next \DN@ ){\xy@{@)}\sleave@ \xyFN@\POS@}%
\else\addAT@\ifx\next \addAT@\DN@{\xy@{@@}{}\smap@}%
\else \DN@##1{\xyerror@{illegal stack command ##1}{}\afterCOORD{\xyFN@\POS@}}%
\fi\fi\fi\fi\fi\fi \next@}
\xydef@\spushc@{%
\count@=\stop@ \advance\count@\@ne \edef\stop@{\the\count@}%
\expandafter\edef\csname S@\stop@\endcsname{\cfromthec@}}
\xydef@\spop@{\count@=\stop@
\ifnum\count@>\sbot@ \advance\count@\m@ne \edef\stop@{\the\count@}%
\else \xyerror@{nothing to pop from stack}{}\fi}
\xydef@\sinit@{\edef\stop@{\sbot@}}
\xydef@\senter@{%
\count@=\stop@ \advance\count@\@ne
\expandafter\edef\csname S@\the\count@\endcsname{\sbot@}%
\edef\sbot@{\the\count@}\edef\stop@{\the\count@}}
\xydef@\sleave@{%
\ifnum\sbot@=\stop@\else
\xywarning@{leaving non-empty stack}\edef\stop@{\sbot@}\fi
\ifnum\sbot@>\m@ne \edef\sbot@{\csname S@\stop@\endcsname}%
\count@=\stop@ \advance\count@\m@ne \edef\stop@{\the\count@}%
\edef\sbot{\the\count@}\fi}
\xydef@\sempty@{\ifnum\stop@=\sbot@ TT\else TF\fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[for every stack element]
%
To `do <coord> for every stack element' means to set $c$ to all the
elements of the stack, from the bottom and up, and for each interpret
the <coord>. Thus the first interpretation has $c$ set to the bottom
element of the stack and the last has $c$ set to~|s0|. If the stack
is empty, the <coord> is not interpreted at all.
This can be used to repeat a particular <coord> for several points:
%
\begin{code}
\xy
@i @+(0,-10) @+(10,3) @+(20,-5)
@@{*{P}}
\endxy
\end{code}
\displaycode
%
\noindent will typeset
%
$$\docode$$
\begin{exercise}
How would you change the above to connect the points as shown below?
%
\begin{code}
\xy
@i @+(0,-10) @+(10,3) @+(20,-5),
s0="prev" @@{;"prev";**\dir{-}="prev"}
\endxy
\end{code}
%
$$\docode$$
%
\answercode
\answertext{This does the job, saving each point to make the previous point
available for the next piece:\displaycode\noindent Notice how we
first save |s0| because that will be the last point that we run
through thus the line is closed.}
%
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|\smap@| maps a <coord> over a stack:
\DOCMODE(
\xydef@\xytotoks@#1#2{\addtotoks@{#2}}
\xydef@\xytotoks@@toksix@#1{\addtotoks@{\toks9={#1}}}
\xydef@\smap@{%
\begingroup \toks@={}\let\xy@=\xytotoks@ \let\oxy@=\xy@
\let\xy@@ix@=\xytotoks@@toksix@
\afterCOORD{\expandafter\endgroup
\expandafter\smapxy@@\expandafter{\the\toks@}\xyFN@\POS@}}
\xydef@\smapxy@@#1{\xy@@{\edef\smapp@@{\sbot@}\smapxy@i{#1}}}
\xylet@\smapp@@=\empty
\xydef@\smapxy@i#1{%
\ifnum\smapp@@<\stop@
\count@=\smapp@@ \advance\count@\@ne \edef\smapp@@{\the\count@}%
\DN@{\csname S@\smapp@@\endcsname #1\relax \smapxy@i{#1}}%
\else \let\next@=\relax
\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[save]??=[saved]
%
It is possible to define new <coord>inates on the form |"|<id>|"| by
"saving" the current $c$ using the \dots|="|<id>|"| <pos>ition form.
Subsequent uses of |"|<id>|"| will then reestablish the $c$ at the
time of the saving.
Using a |"|<id>|"| that was never defined is an error, however,
saving into a name that was previously defined just replaces the
definition, \ie, |"|<id>|"| always refers to the last thing saved
with that <id>.
\NOTE: There is no distinction between <id>s used for saved
coordinates and for macros and described in the next note.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[define macro]
%
The general form, |=|<code>|"|<id>|"| can be used to save various
things:
%
\begin{defs}
<code> & effect \cr
\noalign{\nobreak\smallskip\nobreak\hrule\nobreak\smallskip\nobreak}%
|:| & |"|<id>|"| restores current "base" \cr
<coord> & |"|<id>|"| interprets <coord> \cr
\end{defs}
\noindent\unskip
%
The first form defines |"|<id>|"| to be a macro that restores the
current "base".
The second does not depend on the state at the time of definition at
all; it is a macro definition. You can pass parameters to such a
macro by letting it use coordinates named |"1"|, |"2"|, etc., and
then use |="1"|, |="2"|, etc., just before every use of it to set the
actual values of these. \NOTE: it is not possible to use a <coord>
of the form |"|<id>|"| directly: write it as |{"|<id>|"}|.
%
\begin{exercise}
Write a macro |"dbl"| to double the size of the current~$c$ object,
\eg, changing it from the dotted to the dashed outline in this
figure:
%
\begin{code}
\xy ={.{+DL(2)}.{+UR(2)}}"dbl",
*+<3pc,2pc>{+}*\frm{.}, "dbl"*\frm{--}
\endxy
\end{code}
$$
\docode
$$
\answercode
\answertext{The author used \displaycode\noindent to typeset the figure in
the exercise.}
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This parser distinguishes between the cases:
\DOCMODE(
\xydef@\saveid@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\saveid@}%gobble spaces
\else \ifx "\next\DN@"##1"{\xy@{="##1"}{\idfromc@{##1}}\xyFN@\POS@}%
\else \ifx :\next\DN@:##1"##2"{\xy@{=:"##2"}{\idfrombase@{##2}}\xyFN@\POS@}%
\else \let\next@=\saveid@COORD
\fi\fi\fi \next@}
\DOCMODE)
Here is the code for saving/restoring a position and a base.
\TODO: Introduce |\xyprefix@@| to provide a local scope in addition
to the global one (where it is empty).
\DOCMODE(
\xydef@\xyscope@{}
\xydef@\xyprefix@@{}
\xydef@\idfromc@#1{\DN@{#1}%
\expandafter\edef\csname Q@\codeof\next@\endcsname{\cfromthec@}}
\xydef@\idfrombase@#1{\DN@{#1}%
\expandafter\edef\csname Q@\codeof\next@\endcsname{\basefromthebase@}}
\xydef@\saveid@COORD{%
\begingroup \toks@={}\let\xy@=\xytotoks@ \let\oxy@=\xy@
\let\xy@@ix@=\xytotoks@@toksix@
\afterCOORD{\expandafter\saveid@COORDi\expandafter{\the\toks@}}}
\xydef@\saveid@COORDi#1#2"#3"{\endgroup \xy@@{\idfromxy@{#3}{#1}}\xyFN@\POS@}
\xydef@\idfromxy@#1#2{\DN@{#1}%
\expandafter\def\csname Q@\codeof\next@\endcsname{#2}}
\xydef@\cfromid@#1{\DNii@{#1}\edef\nextii@{\codeof\nextii@}%
\expandafter\let\expandafter\next@\csname Q@\nextii@\endcsname
\ifx\next@\relax
\xyerror@{<pos> \string"\nextii@\string" not defined}{}%
\else \expandafter\next@\fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{notes}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Objects}
??=[object]
\DOCMODE(
\message{objects,}
\DOCMODE)
Objects are the entities that are manipulated with the |*| and |**|
<pos> operations above to actually get some output in \XY-pictures.
As for <pos>itions the operations are interpreted strictly from left
to right, however, the actual object is built "before" all the
<modifier>s take effect. The syntax of objects is given in
figure~??[f.object] with references to the notes below.
\begin{figure*}[tp]
\begin{syntax}
%
??w![<object>]
&\iss & <modifier> <object>
& apply <modifier> to <object>
\cr
&\orr & <objectbox>
& build <objectbox> then apply its <modifier>s
\cr
\noalign{\smallbreak}
%
\cr
??w![<objectbox>]
&\iss & |{| <text> |}|
& ??!^[build default] object
\cr
&\orr & <library object>
& use <library object> (see~\S??[objectlib])
\cr
&\orr & <\TeX\ box> |{| <text> |}|
& ??!^[build box] object with <text> using the given <\TeX\ box>
command, \eg, ??c![\hbox]
\cr
&\orr & ??c![\object] <object>
& wrap up the <object> as a ??!^[finished object box]
\cr
&\orr & ??c![\composite] |{| <composite> |}|
& build ??!^[composite object box]
\cr
&\orr & ??c![\xybox] |{| <pos> <decor> |}|
& package ??!^[entire \XY-picture as object] with the right size
\cr
\noalign{\smallbreak}
%
??w![<modifier>]
&\iss & |!| <vector>
& <object> has its is reference point ??!^[shifted] by <vector>
\cr
&\orr & |!|
& <object> has the original reference point reinstated
\cr
&\orr & <add op> <size>
& change ??!^[<object> size]
\cr
&\orr & ??c![i] \orr\ ??c![h]
& <object> is ??!^[invisible], ??!^[hidden]
\cr
&\orr & |[| <shape> |]|
& <object> is given the specified ??!^[<shape>]
\cr
&\orr & <direction>
& set current direction for this <object>
\cr
\noalign{\smallbreak}
%
??w![<add op>]
&\iss & |+| \orr\ |-| \orr\ |=| \orr\ |+=| \orr\ |-=|
& grow, shrink, set, grow to, shrink to
\cr
\noalign{\smallbreak}
%
??w![<size>]
&\iss & <empty>
& ??!^[default size]
\cr
&\orr & <vector>
& size as sides of rectangle surrounding the <vector>
\cr
\noalign{\smallbreak}
%
??w![<direction>]
&\iss & <diag>
& <diag>onal ??!^[direction]
\cr
&\orr & ??c![v] <vector>
& ??!^[direction] of <vector>
\cr
&\orr & <direction> ??c![:] <vector>
& vector relative to ??!^[<direction>]
\cr
&\orr & <direction> |_| \orr\ <direction> |^|
& $90^\circ$ clockwise/anticlockwise of ??!^[<direction>]
\cr
%
??w![<diag>]
&\iss & <empty>
& default ??!^[diagonal]
\cr
&\orr & |l|\orr|r|\orr|d|\orr|u|
& left, right, down, up ??!^[diagonal]
\cr
&\orr & |ld|\orr|rd|\orr|lu|\orr|ru|
& left/down, \dots\ ??!^[diagonal]
\cr
\noalign{\smallbreak}
%
??w![<composite>]
&\iss & <object>
& first object is required
\cr
&\orr & <composite> |*| <object>
& add <object> to ??!^[composite object box]
%
\end{syntax}
\caption{\protect<object>s.}
??=[f.object]
\end{figure*}
\TODO: Explain how strange \TeX\ error messages (first of all |box
expected|) can result from incomplete <object> specifications.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We first discuss the parser and then summarise the required methods.
The entry point to use of objects is |\object| described in note
??[finished object box]. This should always be used because it
initialises the token list and redefines |\xy@| to be |\addtotoks@|
such that we can use <pos> parser routines within the <object>!
\paragraph*{Parsing:}
The <object> parser |\OBJECT@| will first parse the <modifier>s,
storing the action of each in sequence on the |\toks@| token list.
When there are no more modifiers we insert |\objectbox| if we have
reached the |{| otherwise we just assume that the rest of the
<object> is some kind of box construction.
"Note": The <modifier> actions doing shifts are implemented by having
an independent vector for the shift: $|<|R_p|,|U_p|>|$ always
contains the vector from the current to the original \TeX\ reference
point; furthermore the initial $L_c$ is saved as $L_p$ such that we
can retrieve the original (\XY-pic) reference point again. Modifying
the $p$ values is safe because all actual changes are done in a local
scope after the entire <object> is parsed and we have built the
object box (in |\OBJECT@@|).
The <modifier>s changing the direction are executed while parsing to
make sure that the direction used when building the <object> is
right, and restored in the right sequence while evaluating the
<modifier>s afterwards. This is what |\addDirectiontotoks@| is used
for.
\DOCMODE(
\xydef@\OBJECT@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\OBJECT@}%gobble spaces
\else\ifcat A\noexpand\next \let\next@=\OBJECT@letter
\else \let\next@=\OBJECT@other \fi\fi \next@}
\xydef@\OBJECT@letter{%
\ifx i\next
\DN@ i{\addtotoks@\Invisible@true \xyFN@\OBJECT@}%
\else\ifx h\next
\DN@ h{\addtotoks@\Hidden@true \xyFN@\OBJECT@}%
\else\ifx o\next \DN@ o{\xywarning@{o modifier used}\OBJECT@shape{o}}%
\else\ifx x\next \DN@ x{\xywarning@{x modifier used}\OBJECT@shape{}}%
\else \let\next@=\OBJECT@direction
\fi\fi\fi\fi \next@}
\xydef@\OBJECT@other{%
\ifx !\next \DN@!{\OBJECT@shift}%
\else\addPLUS@\ifx \next \DN@{\OBJECT@change+>}%
\else\addDASH@\ifx \next \DN@{\OBJECT@change-<}%
\else\addEQ@\ifx \next \DN@{\OBJECT@set}%
\else\ifx [\next %]
\DN@[##1]{\xy@{[##1]}{\OBJECT@shape{##1}}}%
\else\ifx ^\next \let\next@=\OBJECT@direction
\else\ifx _\next \let\next@=\OBJECT@direction
\else\ifx :\next \let\next@=\OBJECT@direction
\else\ifx ?\next
\DN@ ?{\xywarning@{\string? modifier used}\xyFN@\OBJECT@direction}%
\else \DN@##1##{\OBJECT@@{##1}}%
\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@}
\xydef@\addDirectiontotoks@{\edef\nextiii@{{\DirectionfromtheDirection@}}%
\expandafter\addtotoks@\nextiii@}
\DOCMODE)
|\OBJECT@@| is where we actually build the box by ??_[OBJ1]~setting
the defaults (including temporarily resetting |\xy@| to execute in
case any |\xy@|s are used internally), ??_[OBJ2]~building the object
box (which might change them) using |\objectbox| if no other command
specified and setting the $D,U,L,R$ dimensions ad required using the
|\Leftness@| and |\Upness@| methods, and finally ??_[OBJ3]~setting up
the $R_p,U_p$ dimensions (as discussed above) and applying the
<modifier>s stored in |\toks@| and dumping the modified box.
\DOCMODE(
\xydef@\OBJECT@@#1#2{\Edgec={\objectEdge}% %?*[OBJ1]
\Invisible@false\Hidden@false \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@\relax}%
\DN@{#1}\ifx\next@\empty \DNii@{#2}% %?*[OBJ2]
\ifx\nextii@\empty \DN@{\hbox\bgroup\no@}\else \let\next@=\objectbox \fi\fi
\setbox\z@=\next@{#2}\Lc=\Leftness@\wdz@ \Rc=\wdz@ \advance\Rc-\Lc
\Dc=\dp\z@ \advance\Dc\ht\z@ \Uc=\Upness@\Dc \advance\Dc-\Uc
% \setbox\z@=\next@{#2}\adjustLR@ \adjustUD@
\Rp=\z@ \Lp=\Lc \Up=\Uc \advance\Up-\ht\z@ \Dp=-\Up %?*[OBJ3]
\the\toks@\toks@={}\setboxz@h{\kern\Rp \raise\Up\boxz@}%
%
\ifdim\Rc=\z@ \ifdim\Uc=\z@ \ifdim\Lc=\z@ \ifdim\Dc=\z@
\Edgec={\zeroEdge}\fi\fi\fi\fi
%
\dimen@=\Lc \advance\dimen@\Rc \wdz@=\dimen@ \ht\z@=\Uc \dp\z@=\Dc \boxz@
\OBJECT@x}
\xydef@\adjustLR@{%
\ifdim\wdz@=\z@ \Lc=\z@ \Rc=\z@ \dimen@=\Leftness@\p@
\ifdim\dimen@<\z@ \Lc=\dimen@ \Rc=-\Lc
\else\ifdim\dimen@>\p@ \Lc=\dimen@ \advance\Lc-\p@ \Rc=-\Lc \fi\fi
\else \Lc=\Leftness@\wdz@ \Rc=\wdz@ \advance\Rc-\Lc \fi }
\xydef@\adjustUD@{\dimen@=\ht\z@ \advance\dimen@\dp\z@
\ifdim\dimen@=\z@ \Uc=\z@ \Dc=\z@ \dimen@=\Upness@\p@
\ifdim\dimen@<\z@ \Uc=\dimen@ \Dc=-\Lc
\else\ifdim\dimen@>\p@ \Uc=\dimen@ \advance\Uc-\p@ \Dc=-\Lc \fi\fi
\else \Dc=\dimen@ \Uc=\Upness@\dimen@ \advance\Dc-\Uc \fi }
\DOCMODE)
As an optimisation |\OBJECT@@| sets the edge type of all zero-sized
objects to |\zeroEdge|.
|\OBJECT@x| cleans up the object by ensuring that it defines all the
required methods: Essentially it terminates the box with the sequence
``|}| |\def\Drop@@{|\dots|}| |\def\Connect@@{|\dots|}| |\Dc=|\dots\
|\Uc=|\dots\ |\Lc=|\dots\ |\Rc=|\dots\ | \Invisible@|\dots
|\Hidden@|\dots\ |\def\Leftness@{|\dots|}| |\def\Upness@{|\dots|}|''
where each \dots\ is set to the method defined within the object
creation environment (started with |\hbox{| in |\OBJECT@@| or
possibly elsewhere). We use rather heavy expansion hacking with
|\toks@| to create the sequence so please look the other
way\dots\smiley
\DOCMODE(
\xydef@\OBJECT@x{\toks@={\egroup\def\Drop@@}%
\expandafter\addtotoks@\expandafter{\expandafter{\Drop@@}\def\Connect@@}%
\expandafter\addtotoks@\expandafter{\expandafter{\Connect@@}}%
\edef\tmp@{\Dc=\the\Dc \Uc=\the\Uc \Lc=\the\Lc \Rc=\the\Rc
\Edgec={\expandafter\noexpand\the\Edgec}%
\ifInvisible@\noexpand\Invisible@true\else\noexpand\Invisible@false\fi
\ifHidden@\noexpand\Hidden@true\else\noexpand\Hidden@false\fi
\def\noexpand\Leftness@{\Leftness@}\def\noexpand\Upness@{\Upness@}}%
\expandafter\addtotoks@\expandafter{\tmp@}\the\toks@}
\DOCMODE)
\paragraph*{Methods:}
??w[object methods]
In addition to the ``current object properties'' for $c$
(\cf~??[basics.state]) the following methods should be set up by
all objects:
\begin{defs}
|\Invisible@true| or |\Invisible@false| & whether object is ??!^[invisible]\cr
|\Hidden@true| or |\Hidden@false| & whether object is ??!^[hidden]\cr
|\def\Leftness@{|<factor>|}| & the desired $L/(L+R)$\cr
|\def\Upness@{|<factor>|}| & the desired $U/(D+U)$\cr
|\def\Drop@@{|\dots|}| & code that outputs the object, assuming |\boxz@| is
of zero size and has the object displaced $|<|X|,|Y|>|$
inside---usually just |\def|'d to |\boxz@|\cr
|\def\Connect@@{|\dots|}| & code that builds a connection from $p$ to $c$,
assuming |\last|\-|object|\-|box@| contains the object\cr
\end{defs}
It is important to |\def| and not |\let| the last four methods since
the \TeX\-nique used in |\OBJECT@x| (and elsewhere) of passing them
to surrounding scopes depends on it. The |\Connect@@| method should
in turn setup several submethods as described in detail in
??[algo.connection].
Suitable defaults are set up by |\OBJECT@@| above which is why any
box generating command can be used to construct objects as explained
in note ??[build default] below.
Here are the declarations:
\DOCMODE(
\xynew@{if}\ifInvisible@
\xynew@{if}\ifHidden@
\xydef@\Leftness@{}
\xydef@\Upness@{}
\xydef@\Drop@@{\boxz@}
\xydef@\Connect@@{}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{notes}
%
\note??=[build default]
%
A default <object> is built using |\object|\-|box| |{|<text>|}|.
|\object|\-|box| is initially defined as
%
\begin{code}
\def\objectbox#1{%
\hbox{$\objectstyle{#1}$}}
\let\objectstyle=\displaystyle
\end{code}
\displaycode
%
but may be redefined by options or the user. The <text> should thus
be in the mode required by the |\objectbox| command---with the
default |\objectbox| it should be in math mode.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Actually it is
\DOCMODE(
\xydef@\objectbox#1{\hbox{$\m@th\objectstyle{#1}$}}
\xylet@\objectstyle=\textstyle
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[build box]
%
An <object> built from a \TeX\ box with dimensions $w*(h+d)$ will
have $L_c=R_c=w/2$, $H_c=D_c=(h+d)/2$, thus initially be equipped
with the adjustment |!C| (see note~??[shifted]). In particular: in
order to get the reference point on the (center of) the base line of
the original <\TeX~box> then you should use the <modifier> |!|; to
get the reference point identical to the \TeX\ reference point use
the modifier |!!L|.
\TeX\-nical remark: Any macro that expands to something that starts
with a <box> may be used as a <\TeX~box> here.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is done by the parsing above.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[finished object box]
%
Takes an object and constructs it, building a box; it is then
processed according to the preceeding modifiers. This form makes it
possible to use any <object> as a \TeX\ box (even outside of
\XY-pictures) because a finished object is always also a box.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This macro is the main entry point to the <object> parser.
\DOCMODE(
\xydef@\object{\hbox\bgroup\object@}
\xydef@\object@{%
\edef\next@{={\DirectionfromtheDirection@}}\expandafter\toks@\next@
\plainxy@ \xyFN@\OBJECT@}
\DOCMODE)
The initial value of |\toks@| <modifier> list is explained in
note~??[direction] below.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[composite object box]
%
Several <object>s can be combined into a single object using the
special command |\composite| with a list of the desired objects
separated with |*|s as the argument. The resulting box (and object)
is the least rectangle enclosing all the included objects.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
First we collect all the objects smash on top of each other in box0
while we maintain the maximal extents in $(DULR)_p$. Then we reset
box0 to contain the same but with the right spacing around.
\DOCMODE(
\xydef@\composite#1#{\hbox\bgroup\composite@{#1}}
\xydef@\composite@#1#2{%
\DN@{#1}\ifx\next@\empty\else\xywarning@{no variants of
\string\composite\space allowed}\fi
\global\setbox9=\hbox\bgroup
\Dp=-\maxdimen \Up=-\maxdimen \Lp=-\maxdimen \Rp=-\maxdimen
\xyFN@\composite@i#2@}
\xydef@\composite@i{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\composite@i}%gobble spaces
\else\ifx *\next \DN@ *{\xyFN@\composite@i}%
\else\ifx @\next \DN@ @{\composite@x}%
\xyerror@{<composite> object expected}{}\czeroEdge@
\else \DN@{\composite@ii}\fi\fi\fi \next@}
\xydef@\composite@ii#1#{\composite@iii{#1}}
\xydef@\composite@iii#1#2{%
\setbox\z@=\object#1{#2}%
\ifInvisible@ \setboxz@h{}%
\else \setboxz@h{\kern-\Lc \boxz@}\ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ {\Drop@@}\fi
\ifHidden@\else
\ifdim\Up<\Uc \Up=\Uc \fi \ifdim\Dp<\Dc \Dp=\Dc \fi
\ifdim\Rp<\Rc \Rp=\Rc \fi \ifdim\Lp<\Lc \Lp=\Lc \fi
\fi
\xyFN@\composite@iv}
\xydef@\composite@iv{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\composite@iv}%gobble spaces
\else \ifx @\next \DN@ @{\composite@x}%
\else \let\next@=\composite@i \fi\fi \next@}
\xydef@\composite@x{%
\edef\tmp@{\egroup \Dc=\the\Dp \Uc=\the\Up \Lc=\the\Lp \Rc=\the\Rp}\tmp@
\setboxz@h{\kern\Lc\box9}\ht\z@=\Uc \dp\z@=\Dc
\dimen@=\Lc \advance\dimen@\Rc \wdz@=\dimen@
\Edgec={\rectangleEdge}\computeLeftUpness@ \boxz@
\OBJECT@x}
\xydef@\computeLeftUpness@{%
\dimen@=\Lc \advance\dimen@\Rc
\ifdim\dimen@=\z@ \def\Connect@@{\straight@{\dottedSpread@\jot}}%
\ifdim\Lc=\z@\else
\DN@{\zeroEdge}\expandafter\DNii@\expandafter{\the\Edgec}%
\ifx\next@\nextii@\Edgec={\rectangleEdge}\fi\fi
\else \quotient@\Leftness@\Lc\dimen@ \fi
\dimen@=\Uc \advance\dimen@\Dc
\ifdim\dimen@=\z@ \def\Connect@@{\straight@{\dottedSpread@\jot}}%
\ifdim\Uc=\z@\else
\DN@{\zeroEdge}\expandafter\DNii@\expandafter{\the\Edgec}%
\ifx\next@\nextii@\Edgec={\rectangleEdge}\fi\fi
\else \quotient@\Upness@\Uc\dimen@ \fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note ??=[entire \XY-picture as object]
%
Take an entire \XY-picture and wrap it up as a box as described
in~\S??[basics.pos]. Makes nesting of \XY-pictures possible: the
inner picture will have its own zero point which will be its
reference point "in" the outer picture when it is placed there.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is simple exploiting the fact that |\endxy| actually sets up the
extents of the `object':
\DOCMODE(
\xydef@\xybox#1{\xy#1\endxy \Edgec={\rectangleEdge}\computeLeftUpness@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[shifted]
%
An object is "shifted" a <vector> by moving the point inside it which
will be used as the reference point. This effectively pushes the
object the same amount in the opposite direction.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Shifting uses the special value of $R_p$ and $U_p$ used while
evalutaing the <modifier>s. The fact that shifts like |!C| refer to
the initial object's size means that we should parse the <vector>
such that its actions happen at modification time\dots hence
|\xytotoks@| is used to delay execution.
\DOCMODE(
\xydef@\OBJECT@shift{%
\let\xy@=\xytotoks@ \afterVECTORorEMPTY
{\OBJECT@shift@}%
{\addtotoks@{\Xc=-\Lc \advance\Xc\Rp \advance\Xc\Lp \Yc=\Up}\OBJECT@shift@}}
\xydef@\OBJECT@shift@{%
\addtotoks@{\advance\Up-\Yc
\advance\Lc\Xc \advance\Rc-\Xc \advance\Dc\Yc \advance\Uc-\Yc
\computeLeftUpness@}%
\let\xy@=\oxy@
\xyFN@\OBJECT@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{exercise}
What is the difference between the <pos>itions |0*{a}!DR| and
|0*!DR{a}|?
\answertext{The first typesets ``$a$'' centered around |0| and then moves $c$
to the lower right corner, the second typesets ``$a$'' above the |0|
point and does not change $c$. With a ``$+$'' at |0| they look like
this: $\vcenter{\xy*{+}*{a}!DR\endxy}$ and
$\vcenter{\xy*{+}*!DR{a}\endxy}$.}%
\end{exercise}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[<object> size]??=[change size]??=[<size>]??=[default size]
%
A <size> is a pair $|<|W|,|H|>|$ of the width and height of a
rectangle. When given as a <vector> these are just the vector
coordinates, \ie, the <vector> starts in the lower left corner and
ends in the upper right corner. The posible <add op>erations that
can be performed are described in the following table.
$$
\begin{array}{\otherbar c\otherbar l\otherbar}
\hline
\hbox{<add op>} & \hbox{description} \\
\hline
|+| & \hbox{grow} \\
|-| & \hbox{shrink} \\
|=| & \hbox{set to} \\
|+=| & \hbox{grow to at least} \\
|-=| & \hbox{shrink to at most} \\
\hline
\end{array}
$$
In each case the <vector> may be omitted which invokes the ``default
size'' for the particular <add op>:
$$
\begin{array}{\otherbar c\otherbar l\otherbar}
\hline
\hbox{<add op>} & \hbox{default}\\
\hline
|+| & |+<|2*"objectmargin"|>| \\
|-| & |-<|2*"objectmargin"|>| \\
|=| & |=<|"objectwidth"|,|"objectheight"|>| \\
|+=| & |+=<|\max(L_c+R_c,D_c+U_c)|>| \\
|-=| & |-=<|\min(L_c+R_c,D_c+U_c)|>| \\
\hline
\end{array}
$$
The defaults for the first three are set with the commands
%
\begin{defs1}
|\objectmargin| <add op> |{|<dimen>|}| \cr
|\objectwidth| <add op> |{|<dimen>|}| \cr
|\objectheight| <add op> |{|<dimen>|}| \cr
\end{defs1}
\noindent\unskip
%
where <add op> is interpreted in the same way as above.
\DOCMODE(
\xylet@\objectmargin@=\jot
\xylet@\objectwidth@=\z@
\xylet@\objectheight@=\z@
\xydef@\objectmargin{\afterADDOP{\Addop@@\objectmargin@}}
\xydef@\objectwidth{\afterADDOP{\Addop@@\objectwidth@}}
\xydef@\objectheight{\afterADDOP{\Addop@@\objectheight@}}
\DOCMODE)
The defaults for |+=|/|-=| are such that the resulting object will be
the smallest containing/largest contained square.
\begin{exercise}
How are the objects typeset by the <pos>itions ``|*+UR{\sum}|'' and
``|*+DL{\sum}|'' enlarged?
\answertext{They have the outlines
$$\xy*+UR{\sum}*\frm{-}*{+}\endxy
\quad\text{and}\quad
\xy*+DL{\sum}*\frm{-}*{+}\endxy$$
because the first is enlarged by the positive offset to the upper
right corner and the second by the negative offset to the lower left
corner.}
\end{exercise}
\BUG: Currently changing the size of a circular object is buggy---it
is changed as if it is a rectangle and then the change to the $R$
parameter affects the circle. This should be fixed probably by a
generalisation of the |o| shape to be ovals or ellipses with
horizontal/vertical axes.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The three cases distinguished by the parsing above are handled
similarly: they insert the parsed/default vector into $X,Y$ in the
modifications and then perform the operation at that time using the
|\xytotoks@| trick described in note~??[shifted]:
\DOCMODE(
\xydef@\OBJECT@change#1#2{%
\afterADDOP{%
\addEQ@\ifx \next
\addtotoks@{\Xc=\Dc \advance\Xc\Uc \Yc=\Lc \advance\Yc\Rc}%
\else
\addtotoks@{\Xc=\objectmargin@ \advance\Xc\Xc \Yc=\Xc}%
\fi
\let\xy@=\xytotoks@
\afterVECTORorEMPTY{\OBJECT@change@#1#2}{\OBJECT@change@#1#2}}}
\xydef@\OBJECT@set{%
\afterADDOP{%
\let\xy@=\xytotoks@ \afterVECTORorEMPTY
{\OBJECT@change@+=}%
{\addtotoks@{\Xc=\objectwidth@ \Yc=\objectheight@}\OBJECT@change@+=}}}
\DOCMODE)
The real work is done by the following command: a hack using
expansion tricks to make use of the |\Addop@@| known now on the
values in $X,Y$ at modification time.
\DOCMODE(
\xydef@\OBJECT@change@#1#2{%
\addtotoks@{\advance\Rc\Lc \advance\Rp-\Lc \let\tmp@=\Rc}%
\expandafter\addtotoks@\expandafter{\Addop@@\tmp@{#1\Xc}\Rc=\tmp@
\Lc=\Leftness@\Rc \advance\Rp\Lc \advance\Rc-\Lc}%
\addtotoks@{\advance\Dc\Uc \let\tmp@=\Dc}%
\expandafter\addtotoks@\expandafter{\Addop@@\tmp@{#1\Yc}\Dc=\tmp@
\Uc=\Upness@\Dc \advance\Dc-\Uc}%
\let\xy@=\oxy@ \xyFN@\OBJECT@}
\DOCMODE)
It is clearly crucial that |\Addop@@| expands to its action
immediately! Also note that enlarging changes the initial box offset
in the horizontal direction only, \ie, $R_p$.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Finally the code to interpret an <add op> used above: This
simply parses it and creates a macro |\Addop@@| that takes a
control sequence and a parameter <dimen> as arguments, and
expands directly to commands that perform the <add op> of the
<dimen> on the control sequence:
$$
\begin{array}{\otherbar c\otherbar l\otherbar}
\hline
\hbox{<add op>} & \hbox{effect of |\Addop@@| "cs" $D$} \\
\hline
|+| & "cs" \from "cs"+D \\
|-| & "cs" \from "cs"-D \\
|=| & "cs" \from D \\
|+=| & "cs" \from \left\{
\begin{array}{cc} D & \hbox{if $D\le"cs"$} \\
"cs" & \hbox{if $D\gt"cs"$} \end{array}\right.
\\[1pt]
|-=| & "cs" \from \left\{
\begin{array}{cc} D & \hbox{if $D\ge"cs"$} \\
"cs" & \hbox{if $D\lt"cs"$} \end{array}\right.
\\[1pt]
\hline
\end{array}
$$
Furthermore |\afterADDOP| leaves the |\next| token set to |=| in the
last three cases only (this is used to determine the right default
value in the size changes above).
The |\afterADDOP| macro is relatively simple because <add op>s don't
nest:
\DOCMODE(
\xydef@\afterADDOP#1{\def\afterADDOP@{#1}\xyFN@\ADDOP@}
\xylet@\afterADDOP@=\empty
\xydef@\ADDOP@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\ADDOP@}%gobble spaces
\else\addPLUS@\ifx \next \addPLUS@\DN@{\xyFN@\ADDOP@plus}%
\else\addDASH@\ifx \next \addDASH@\DN@{\xyFN@\ADDOP@minus}%
\else\addEQ@\ifx \next
\addEQ@\DN@{\def\Addop@@{\Addop@0+=}\afterADDOP@}%
\else
\DN@{\def\Addop@@{\Addop@0+=}\afterADDOP@}%
\fi\fi\fi\fi \next@}
\xydef@\ADDOP@plus{%
\addEQ@\ifx \next
\addEQ@\DN@{\def\Addop@@{\Addop@0+<}\afterADDOP@}%
\else
\DN@{\def\Addop@@{\Addop@1+=}\afterADDOP@}%
\fi \next@}
\xydef@\ADDOP@minus{%
\addEQ@\ifx \next
\addEQ@\DN@{\def\Addop@@{\Addop@0->}\afterADDOP@}%
\else
\DN@{\def\Addop@@{\Addop@1-=}\afterADDOP@}%
\fi \next@}
\DOCMODE)
The work is done by the general |\Addop@| |{|$f$|}| |{|$\pm_1$|}|
|{|$\pm_2$|}| |{|"cs"|}| $D$ that defines
$$
"cs" \equiv \left\{
\begin{array}{ll}
f*"cs"~{\pm_1}~D& \hbox{if $\lnot ((f*"cs"~{\pm_1}~D)~{\pm_2}~D)$} \\
"cs" & \hbox{otherwise} \end{array}\right.
$$
and also leaves the dimension in |\dimen@|.
\DOCMODE(
\xydef@\Addop@#1#2#3#4#5{%
\dimen@=#4\relax \edef#4{\the\dimen@}%
\dimen@=#1\dimen@ \advance\dimen@#2#5\relax
\ifdim\dimen@#3#4\else \edef#4{\the\dimen@}\fi
\ifx\xy@\xyinitial@\else \DN@##1{\xy@@{\edef#4{##1}}}%
\expandafter\next@\expandafter{#4}\fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[invisible]
%
An "invisible" object will be treated completely normal except that
it won't be typeset, \ie, \XY-pic will behave as if it was.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is handled by the |\ifInvisible@| conditional allocated with the
methods.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[hidden]
%
A "hidden" object will be typeset but hidden from \XY-pic in that it
won't affect the size of the entire picture as discussed
in~\S??[basics.pos].
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is handled by the |\ifHidden@| conditional allocated with the
methods.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[<shape>]
%
Setting the "shape" of an object forces the shape of its edge to be
as indicated: the kernel just provides the three shapes |[.]|, |[]|,
and |[o]|, corresponding to the outlines
$$
\let\objectstyle=\scriptstyle
\xy*{*}\endxy
\quad
\text{,}
\quad
\xy(0,0).(-10,-4).(15,7)*\frm{-}="box"*{*}+0;
"box"+L*{}**\dir{.}?*{L},
"box"+R*{}**\dir{.}?*{R},
"box"+D*{}**\dir{.}?*{D},
"box"+U*{}**\dir{.}?*{U}
\endxy
\quad
\text{, and}
\quad
\xy*[o]=<40pt>{*}="box"*\cir{}+0;
"box"+L*{}**\dir{.}?*{L},
"box"+R*{}**\dir{.}?*{R},
"box"+D*{}**\dir{.}?*{D},
"box"+U*{}**\dir{.}?*{U}
\endxy
$$
where the $*$ denotes the point of the reference position in the
object (the first is a point). Extensions can provide more shapes,
however, all shapes set the extent dimensions $L$, $R$, $D$,
and $U$.
The default shape for objects is |[]| and for plain coordinates it is
|[.]|.
\DOCMODE(
\xydef@\objectEdge{\rectangleEdge}
\DOCMODE)
\NOTE: Extensions may add <shape> object <modifier>s of two kinds:
either |[|<keyword>|]| or |[|<character> <argument>|]|. Some of
these <shape>s do other things than set the edge of the object.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
A ``simple shape'' is just a control sequence |\*shape@|<shape>|@|
setting the appropriate edge. When such a |[|<shape>|]| modifier is
encountered then we expand this control sequence onto the modifier
queue.
\DOCMODE(
\xydef@\OBJECT@shape#1{\DN@{*shape@#1@}%
\expandafter\let\expandafter\next\csname\codeof\next@\endcsname
\ifx\next\relax \DN@{\OBJECT@shapei[#1]}%
\else \DN@{\expandafter\addtotoks@\expandafter{\next}\xyFN@\OBJECT@}\fi
\next@}
\xydefcsname@{*shape@@}{\the\Edgec4}
\xydefcsname@{*shape@o@}{\Edgec={\circleEdge}\Lc=\Rc \Uc=\Rc \Dc=\Rc}
\xydefcsname@{*shape@.@}{\czeroEdge@}
\DOCMODE)
Add more simple shapes by defining more commands like these and
proceed with coding the |\|\dots|Edge| command as described
in~\S??[algo.edge].
Alternatively it is a ``complex shape'' of which none are defined in
the kernel but some options like more variation\dots It is
characterised by its first token and the rest of the contents of the
|[]|s is the argument (remember: no |{}[]| characters!)
\DOCMODE(
\xydef@\OBJECT@shapei[#1#2]{\DN@{*shapechar@#1@}%
\expandafter\let\expandafter\next\csname\codeof\next@\endcsname
\ifx\next\relax \DN@{[#1#2]}%
\xywarning@{illegal [<shape>] ignored: \codeof\next@\space not defined}%
\else \expandafter\addtotoks@\expandafter{\next{#2}}\fi
\xyFN@\OBJECT@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[diagonal]??=[direction]??=[<direction>]
%
Setting the current direction is simply pretending for the
typesetting of the object (and the following <modifier>s) that some
connection set it.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The code just calls the general <direction> parser below:
\DOCMODE(
\xydef@\OBJECT@direction{\afterDIRECTIONorEMPTY{%
\edef\next@{{\DirectionfromtheDirection@}}\expandafter\addtotoks@\next@
\xyFN@\OBJECT@}%
{\xyFN@\OBJECT@}}
\DOCMODE)
Here is the <direction> parser: first the parts parsing the <diag>
part then the parts parsing the <trailer> part:
\DOCMODE(
\xydef@\afterDIRECTIONorEMPTY#1#2{%
\DN@##1{\def\afterDIRECTION@{\def\afterDIRECTION@{##1}%
\ifDIRECTIONempty@\DN@{#2}\else\DN@{#1}\fi \next@}}%
\expandafter\next@\expandafter{\afterDIRECTION@}%
\xyFN@\DIRECTION@}
\xylet@\afterDIRECTION@=\empty
\xynew@{if}\ifDIRECTIONempty@
\xydef@\DIRECTION@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\DIRECTION@}%gobble spaces
\else\ifx v\next \DN@ v{\DIRECTION@v}%
\else
\DN@{\count@=8 %
\afterDIAG{\ifnum\count@=8 \DN@{\DIRECTIONempty@true \xyFN@\DIRECTION@i}%
\else \DN@{\xy@@{\dimen@=\xydashl@}\Directionfromdiag@}\fi \next@}}%
\fi\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
It is particularly easy to set absolute, <diag>onal directions:
$$
\xy *[o]\cir<1pc>{}="c",
"c"; (-1,-1)**{},p+/4pc/ *+{|dl|=|ld|} **\dir{-}?>*\dir{>},
"c"; ( 0,-1)**{},p+/4pc/ *+{|d|} **\dir{-}?>*\dir{>},
"c"; ( 1,-1)**{},p+/4pc/ *+{|dr|=|rd|} **\dir{-}?>*\dir{>},
"c"; ( 1, 0)**{},p+/4pc/ *+{|r|} **\dir{-}?>*\dir{>},
"c"; ( 1, 1)**{},p+/4pc/ *+{|ur|=|ru|} **\dir{-}?>*\dir{>},
"c"; ( 0, 1)**{},p+/4pc/ *+{|u|} **\dir{-}?>*\dir{>},
"c"; (-1, 1)**{},p+/4pc/ *+{|ul|=|lu|} **\dir{-}?>*\dir{>},
"c"; (-1, 0)**{},p+/4pc/ *+{|l|} **\dir{-}?>*\dir{>},
\endxy
$$
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
<diag>onals are stored internally as
$$
\xy *\cir<1pc>{}="c",
"c"; (-1,-1)**{},p+/3pc/ *+{|0|} **\dir{-}?>*\dir{>},
"c"; ( 0,-1)**{},p+/3pc/ *+{|1|} **\dir{-}?>*\dir{>},
"c"; ( 1,-1)**{},p+/3pc/ *+{|2|} **\dir{-}?>*\dir{>},
"c"; ( 1, 0)**{},p+/3pc/ *+{|3|} **\dir{-}?>*\dir{>},
"c"; ( 1, 1)**{},p+/3pc/ *+{|4|} **\dir{-}?>*\dir{>},
"c"; ( 0, 1)**{},p+/3pc/ *+{|5|} **\dir{-}?>*\dir{>},
"c"; (-1, 1)**{},p+/3pc/ *+{|6|} **\dir{-}?>*\dir{>},
"c"; (-1, 0)**{},p+/3pc/ *+{|7|} **\dir{-}?>*\dir{>},
\endxy
$$
Expanding |\afterDIAG{|<stuff>|}|<diag> will result in |\count@|
being set to the <diag> code (not changed in case the <diag> is
<empty>) before expanding <stuff>.
\DOCMODE(
\def\afterDIAG#1{\def\afterDIAG@{#1}\xyFN@\DIAG@}
\xydef@\DIAG@{%
\ifx d\next \DN@ d{\count@=1 \xyFN@\DIAG@@}%
\else\ifx r\next \DN@ r{\count@=3 \xyFN@\DIAG@@}%
\else\ifx u\next \DN@ u{\count@=5 \xyFN@\DIAG@@}%
\else\ifx l\next \DN@ l{\count@=7 \xyFN@\DIAG@@}%
\else \let\next@=\afterDIAG@
\fi\fi\fi\fi \next@}
\xydef@\DIAG@@{\ifcase\count@ \or
%\count@=1 3 5 7
\DIAG@@@ l0r2\or\or \DIAG@@@ d2u4\or\or \DIAG@@@ r4l6\or\or \DIAG@@@ u6d0%
\else\xybug@{impossible <diag> number}\fi
\next@}
\xydef@\DIAG@@@#1#2#3#4{%
\ifx #1\next \count@=#2\DN@#1{\afterDIAG@}%
\else \ifx #3\next \count@=#4\DN@#3{\afterDIAG@}%
\else \let\next@=\afterDIAG@ \fi\fi}
\DOCMODE)
The action in case of a <diag> is simply to pick the right direction
setup routine according to the encoding, getting the <diag> from
|\count@| and the length of the $d$ vector from |\dimen@|:
\DOCMODE(
\xydef@\Directionfromdiag@{\ifcase\count@
\xy@@{\dlDirection@\dimen@}%
\or \xy@@{\dDirection@\dimen@}%
\or \xy@@{\drDirection@\dimen@}%
\or \xy@@{\rDirection@\dimen@}%
\or \xy@@{\urDirection@\dimen@}%
\or \xy@@{\uDirection@\dimen@}%
\or \xy@@{\ulDirection@\dimen@}%
\or \xy@@{\lDirection@\dimen@}%
\or % 8 is legal and means change nothing
\else\xybug@{impossible <diag>}\fi
\DIRECTIONempty@false\xyFN@\DIRECTION@i}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Alternatively |v|<vector> sets the direction as if the connection
from |0| to the <vector> had been typeset except that the "origin" is
assumed zero such that directions $|v(|x|,|y|)|$ mean the natural
thing, \ie, is the direction of the connection from |(0,0)| to
$|(|x|,|y|)|$. With the initial coordinate system this means that
the directions |ur| and |v(1,1)| are identical.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The action for a |v| reads a <vector> and sets the direction
accordingly using some expansion hackery to propagate it out. The
"origin" is cleared locally to make |v(|$x$|,|$y$|)| behave as it
should, \ie, use the direction of
\DOCMODE(
\xydef@\DIRECTION@v{\begingroup \xy@{v}{\Xorigin=\z@ \Yorigin=\z@}%
\afterVECTORorEMPTY
{\xy@@{\Xp=\z@ \Yp=\z@ \setupDirection@}%
\edef\next@{\noexpand\xy@@\DirectionfromtheDirection@}%
\expandafter\endgroup\next@ \DIRECTIONempty@false \xyFN@\DIRECTION@i}%
{\xyerror@{<vector> expected after v}{}\endgroup
\DIRECTIONempty@false \xyFN@\DIRECTION@i}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Once the initial direction is established as either the last one or
an absolute one then the remainder of the direction is interpreted.
Adding |_| and |^| denote the result of rotating the default
direction a right angle in the positive and negative direction.
A trailing |:|<vector> is like |v|<vector> but uses the
<direction> to set up a standard square base such that |:(0,1)| and
|:a(90)| mean the same as |^| and |_| is equivalent to |:(0,-1)| and
|:a(-90)|.
\DOCMODE(
\xydef@\DIRECTION@i{%
\ifx ^\next \DN@ ^{\xy@^{\aboveDirection@\xydashl@}%
\DIRECTIONempty@false \xyFN@\DIRECTION@i}%
\else\ifx _\next \DN@ _{\xy@_{\belowDirection@\xydashl@}%
\DIRECTIONempty@false \xyFN@\DIRECTION@i}%
\else\ifx :\next \DN@ :{\begingroup
\xy@:{\Xorigin=\z@ \Yorigin=\z@
\Xxbase=\dX \Yxbase=\dY \Xybase=-\dY \Yybase=\dX}%
\afterVECTORorEMPTY
{\xy@@{\Xp=\z@ \Yp=\z@ \setupDirection@}%
\edef\next@{\noexpand\xy@@\DirectionfromtheDirection@}%
\expandafter\endgroup\next@ \DIRECTIONempty@false \xyFN@\DIRECTION@i}%
{\xyerror@{<vector> expected after \string:}{}\endgroup
\DIRECTIONempty@false \xyFN@\DIRECTION@i}}%
\else
\let\next@=\afterDIRECTION@
\fi\fi\fi \next@}
\DOCMODE)
\TODO: Allow |:a(|<angle>|)|.
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{exercise}
What is the effect of the <modifier>s |v/1pc/| and |v/-1pc/|?
\answertext{The first has no effect since the direction is set to be that of
a vector in the current direction, however, the second reverses the
current direction.}
\end{exercise}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{notes}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Decorations}
??=[decor]
\DOCMODE(
\message{decorations;}
\DOCMODE)
<Decor>ations are actual \TeX\ macros that decorate the current
picture in manners that depend on the state. They are used "after"
the <pos>ition either of the outer |\xy|\dots|\endxy| or inside
|{|\dots|}|. The possibilities are given in figure~??[f.decor] with
notes below.
\begin{figure*}[tp]
\vss
\begin{syntax}
??w![<decor>]
&\iss & <command> <decor>
& either there is a command\dots
\cr
&\orr & <empty>
& \dots or there isn't.
\cr
??w![<command>]
&\iss & |\save| <pos>
& save ??!^[state] for restoration by later |\restore|, then do <pos>
\cr
&\orr & |\restore|
& restore ??!^[state] saved by matcing |\save|
\cr
&\orr & |\POS| <pos>
& interpret <pos>
\cr
&\orr & |\afterPOS| |{| <decor> |}| <pos>
& interpret <pos> and then perform <decor>
\cr
&\orr & |\drop| <object>
& drop <object> as the <pos> |*| operation
\cr
&\orr & |\connect| <object>
& connect with <object> as the <pos> |**| operation
\cr
&\orr & |\relax|
& do nothing
\cr
&\orr & <\TeX\ commands>
& any ??!^[\TeX\ commands] and user defined macros that neither
generates output (watch out for spaces!) nor changes the grouping
may be used
\cr
&\orr & |\xyverbose| \orr\ |\xytracing| \orr\ |\xyquiet| \kern-3pc
& \kern3pc ??!^[tracing] commands
\cr
&\orr & |\xyignore| |{|<pos> <decor>|}|
& ??!^[ignore] \XY-code
\cr
&\orr & |\xycompileto| |{|<name>|}| |{|<pos> <decor>|}| \kern-3pc
& \kern3pc ??!^[compile] to file <name>|.xyc|
\cr
\end{syntax}
\caption{\protect<decor>ations.}
??=[f.decor]
\vfill
\end{figure*}
Most options add to the available <decor>, in particular the |v2|
option loads many more since \XY-pic versions prior to 2.7 provided
most features as <decor>.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Simple decorations:}
|\POS| and |\afterPOS| have already been defined; the following are
just simple applications of previously defined commands:
\DOCMODE(
\xydef@\drop#1#{\DN@##1{\xy@@ix@{{#1}{##1}}%
\xy@{\drop#1{##1}}{\expandafter\drop@\the\toks9}\ignorespaces}\next@}
\xydef@\connect#1#{\DN@##1{\xy@@ix@{{#1}{##1}}%
\xy@{\connect#1{##1}}{\expandafter\connect@\the\toks9}\ignorespaces}\next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{notes}
%
\note??=[state]
%
Saving and restoring allows `excursions' where lots of things are
added to the picture without affecting the resulting \XY-pic state,
\ie, $c$, $p$, and "base", and without requiring matching |{}|s. The
independence of |{}| is particularly useful in conjunction with the
|\afterPOS| command, for example, the definition
\begin{code}
\def\ToPOS{\save\afterPOS{%
\POS**{}?>*\dir2{>}**\dir2{-}
\restore};p,}
\end{code}
\gdocode
\displaycode
will make the code |\ToPOS| <pos> make a double arrow from the
current object to the <pos> (computed relative to it) such that
%
\begin{code}
\xy *{A} \ToPOS +<10mm,2mm> \endxy
\end{code}
%
\thecode\ will typeset the picture \docode.
\paragraph*{Note:}
Saving this way in fact uses the same state as the |{}| `grouping',
so the code $p_1$|,| |{|$p_2$|\save},| \dots\ |{\restore}| will have
$c=p_1$ both at the \dots\ and at the end!
\DOCMODE(
\xydef@\save{\xy@\save\save@ \POS}
\xydef@\save@{\enter@{\cfromthec@ \pfromthep@ \basefromthebase@}}
\xydef@\restore{\xy@\restore\leave@ \ignorespaces}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[\TeX\ commands]
%
One very tempting kind of \TeX\ commands to perform as <decor> is
arithmetic operations on the \XY-pic state. This will work in simple
\XY-pictures as described here but be warned: "it is not portable"
because all \XY-pic execution is indirect, and this is used by
several options in nontrivial ways. Check the \TeX-nical
documentation~\cite{R94:XY-picCSTC} for details about this!
Macros that expand to <decor> will always do the same, though.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\TeX\ hackers like the author may enjoy changing the \XY-pic state
directly using <decor> of the form |\xy@{|<id>|}{|<code>|}|\dots
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[tracing]
%
|\xyverbose| will switch on a tracing of all the \XY-pic commands
executed. |\xytracing| traces even more: the entire \XY-pic state is
printed after each modification. |\xyquiet| restores default quiet
operation.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The trick is to replace the |\xy@| command such that it calls the
`normal' one between writing out a trace message and the state.
\DOCMODE(
\xydef@\xyverbose{\xy@\xyverbose{\let\xy@=\xyverbose@
\W@{XY: \string\xyverbose\xytracelineno@}}}
\xydef@\xyverbose@#1#2{%
{\def\1{#1}\ifx\1\empty\else\W@{XY: \codeof\1\xytracelineno@}\fi}%
\oxy@{#1}{#2}}
\xydef@\xytracing{\xy@\xytracing{\let\xy@=\xytracing@
\W@{XY TRACE: \string\xytracing\xytracelineno@}\xystatus@:}}
\xydef@\xytracing@#1#2{{\def\1{#1}\def\2{#2}%
\W@{XY TRACE: \codeof\1 {\codeof\2}\xytracelineno@}}\oxy@{#1}{#2}\xystatus@:}
\xydef@\xystatus@#1{%
\W@{#1 c=<\the\Xc,\the\Yc> \expandafter\string\the\Edgec
\string[\the\Lc+\the\Rc,\the\Dc+\the\Uc\string]}%
\W@{#1 p=<\the\Xp,\the\Yp> \expandafter\string\the\Edgep
\string[\the\Lp+\the\Rp,\the\Dp+\the\Up\string]}%
\W@{#1 [d=<\the\dX,\the\dY>
Direction=\the\Direction=\string(\cosDirection,\sinDirection\string)]
S=\the\csp@}%
\W@{#1 base = <\the\Xorigin,\the\Yorigin> +
x\string*<\the\Xxbase,\the\Yxbase> +
y\string*<\the\Xybase,\the\Yybase>}%
\W@{#1 min/max = <\the\Xmin,\the\Ymin> / <\the\Xmax,\the\Ymax>}}
\xydef@\xyquiet{\xy@\xyverbose{\let\xy@=\oxy@
\W@{XY: \string\xyverbose\xytracelineno@}}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[ignore]
%
Ignoring means that the <pos> <decor> is still parsed the usual way
but nothing is typeset and the \XY-pic state is not changed.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We ignore in a group to ensure that nothing done inside `leaks' to
the outside.
\DOCMODE(
\xydef@\xyignore#1{\xy@\xyignore{\xyignore@{#1}}\ignorespaces}
\xydef@\xyignore@#1{{\let\xy@=\xyeat@ \let\oxy@=\xy@ \POS#1\relax}}
\xydef@\xyeat@#1#2{}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[compile]
%
It is possible to save the commands to generate parts of an
\XY-picture to a file such that subsequent typesetting of those parts
is significantly faster: this is called "compiling". The created
file will be named <name>|.xyc| and contain code to check that the
compiled code still corresponds to the <pos> <decor> as well as more
efficient compiled code to redo it. If the <pos> <decor> has changed
then the compilation is redone and <name>|.xyc| recreated.
\BUG: Currently you can only compile matrices (built with the matrix
feature) where all entries are empty or start with something that is
unexpandable.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
It is done by just writing all |\xy@|-commands to the file. The file
establishes the correct input mode through use of the appropriate
commands itself.
\DOCMODE(
\xylet@\compilename@@=\empty
\xylet@\xyrecompile@@=\relax
\xydef@\xycompileto#1#2{\if\inxy@ \DN@{\xy@@{\nter@{}}}%
\else \DN@{\xy \xy@@{\nter@\endxy}}\fi \next@
\ifxysaving@ \xyerror@{Compilations can not be nested}{}\fi
\DN@{#1}\edef\compilename@@{\codeof\next@}\DNii@{#2}%
\expandafter\xyinputorelse@\expandafter{\compilename@@.xyc}%
{\def\xyrecompile@@{compiling new}}%
\ifx\xyrecompile@@\relax\else \expandafter\xyrecompile@ \fi \xy@@\leave@}
\DOCMODE)
Recompilation is done by just writing all |\xy@|-commands to the
file. The file establishes the correct input mode and terminates
itself; after it has been finished it is simply reread to actually
get the drawing done in the document.
\DOCMODE(
\xydef@\xyrecompile@{%
\message{(\xyrecompile@@\space\string`\compilename@@.xyc\string'}%
\DN@{\immediate\openout\xywrite@=}\expandafter\next@\compilename@@.xyc
\immediate\write\xywrite@{%
\string\xycompiled{\compilename@@}%
{\the\year/\the\month/\the\day\string:\the\time\xytracelineno@}%
{Xy-pic \xyversion}\xycomment@}%
\immediate\write\xywrite@{{\codeof\nextii@}\relax}%
{\xysaving@ \expandafter\POS\nextii@ \relax}%
\immediate\write\xywrite@{\string\xyendcompiled}%
\immediate\closeout\xywrite@ \message{done)}%
\expandafter\input\compilename@@.xyc }
\xydef@\xysaving@{\let\xy@=\xysave@ \let\oxy@=\xy@
\let\xy@@ix@=\xysave@@toksix@ \xysaving@true}
\xynew@{if}\ifxysaving@ \xysaving@false
\xydef@\xysave@#1#2{{\DN@{\xy@{#1}{#2}}%
\immediate\write\xywrite@{\codeof\next@\xycomment@}}}
\xydef@\xysave@@toksix@#1{{\DN@{\xy@@ix@{#1}}%
\immediate\write\xywrite@{\codeof\next@\relax}}}
\xywarnifdefined\xycomment@
{\catcode`\%=12 \catcode`\(=1 \catcode`\)=2 \gdef\xycomment@(%)}
\DOCMODE)
\HACK{1:} The |\ifxysaving@| can never be locally switched off!
Anyway it is used to allow a gross hack avoiding building a queue in
the matrix option that will generate too long lines!!
\HACK{2:} |\xysave@@toksix@| is not doing the catcode jive because it
can never be invoked while loading a file (knock, knock~\smiley~).
The initial command in all |.xyc| files check that this is the right
file and that neither the version of \XY-pic nor the user's code has
changed:
\DOCMODE(
\xydef@\xycompiled#1#2#3#4{\DN@{#1}\edef\next@{\codeof\next@}%
\ifx\next@\compilename@@\else
\xywarning@{This file does not contain the result of
\string\xycompileto{\compilename@@}{...}^^J%
but of \string\xycompileto{\next@}}\fi
\edef\next{Xy-pic \xyversion}\DN@{#3}\ifx\next\next@
\DN@{#4}\ifx\next@\nextii@ \message{compiled #2}\xycatcodes
\else \def\xyrecompile@@{source changed - recompiling}\xyendinput \fi
\else \def\xyrecompile@@{XY-pic version changed - recompiling}\xyendinput \fi}
\xydef@\xyendcompiled{\let\xyrecompile@@=\relax \xyendinput}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{notes}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Kernel object library}
??=[objectlib]
\DOCMODE(
\message{kernel objects:}
\DOCMODE)
In this section we present the "library objects" provided with the
kernel language---several options add library objects. They fall
into three types: Most of the kernel objects (including all those
usually used with |**| to build connections) are "directionals",
described in \S??[objectlib.directionals]. The remaining kernel
library objects are "circles" of \S??[objectlib.circles] and "text"
of \S??[objectlib.text].
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Directionals}
??=[objectlib.directionals]
\DOCMODE(
\message{directionals,}
\DOCMODE)
The kernel provides a selection of "directionals": objects that
depend on the current direction. They all take the form
%
\begin{defs1}
%
|\dir|<dir> \cr
%
\end{defs1}
\noindent\unskip
%
to typeset a particular <dir>ectional object. All have the structure
%
\begin{defs1}
%
<dir> \iss\ <variant>|{|<main>|}| \cr
%
\end{defs1}
\noindent\unskip
%
with <variant> being <empty> or one of the characters |^_23| and
<main> some mnemonic code.
We will classify the directionals primarily intended for building
connections as "connectors" and those primarily intended for
placement at connection ends or as markers as "tips".
\begin{figure*}[t]
%
\def\Dx#1#2{\hbox{\def\1{#1{#2}}\enspace\tt\string\dir\codeof\1}}
%
\def\DC#1#{\DCx{#1}}
\def\DCx#1#2{ \Dx{#1}{#2} & \vcenter{\xy
0*\cir<5pt>{} ; (16,5)*=<10pt>{}*\frm{-} **\dir#1{.} **h\dir#1{#2}
\endxy}}
%
\def\DT#1#{\DTx{#1}}
\def\DTx#1#2{\Dx{#1}{#2} & \vcenter{\xy
-(4,2.5)*{} ; (4,0)*{} **{} ?>*\dir#1{#2} **\dir#1{.}
\endxy}}
%
\def\Darray#1#2{{\let\\=\cr \tabskip=0pt plus 1fil %
\halign to\hsize{&\hfil$##$&$##$\hfil\\
\noalign{\hbox to\hsize{\hss#1\hss}\smallskip}#2\crcr}\bigskip}}
%
\Darray{??!^[Dummy]}{\hbox{\tt\string\dir\string{\string}}}
%
\Darray{??!^[Plain connectors]}{%
\DC{-} &\DC2{-} &\DC3{-} \\
\DC{.} &\DC2{.} &\DC3{.} \\
\DC{~} &\DC2{~} &\DC3{~} \\
\DC{--} &\DC2{--} &\DC3{--} \\
\DC{~~} &\DC2{~~} &\DC3{~~} \\
}
\bigskip
\Darray{??!^[Plain tips]}{%
\DT{>} &\DT^{>} &\DT_{>} &\DT2{>} &\DT3{>} \\
\DT{<} &\DT^{<} &\DT_{<} &\DT2{<} &\DT3{<} \\
\DT{|} &\DT^{|} &\DT_{|} &\DT2{|} &\DT3{|} \\
\DT{(} &\DT^{(} &\DT_{(} \\
\DT{)} &\DT^{)} &\DT_{)} \\
& &\DT^{`} &\DT_{`} \\
& &\DT^{'} &\DT_{'} \\
}
\bigskip
\Darray{??!^[Constructed tips]}{%
\DT{>>} &\DT^{>>} &\DT_{>>} &\DT2{>>} &\DT3{>>} \\
\DT{<<} &\DT^{<<} &\DT_{<<} &\DT2{<<} &\DT3{<<} \\
\DT{||} &\DT^{||} &\DT_{||} &\DT2{||} &\DT3{||} \\
\DT{|-} &\DT^{|-} &\DT_{|-} &\DT2{|-} &\DT3{|-} \\
\DT{>|} &\DT{>>|} &\DT{|<} &\DT{|<<} \\
\DT{+} &\DT{x} &\DT{/} &\DT{*} &\DT{o} \\
}
\caption{Kernel library \protect<dir>ectionals}??=[f.dir]
\end{figure*}
Figure~??[f.dir] shows all the <dir>ectionals defined by the kernel
with notes below; each <main> type has a line showing the available
<variant>s. Notice that only some variants exist for each
<dir>---when a nonexisting variant of a <dir> is requested then the
<empty> variant is used silently. Each is shown in either of the two
forms available in each direction as applicable: connecting a
$\bigcirc$ to a $\Box$ (typeset by |**\dir|<dir>) and as a tip at the
end of a dotted connection of the same variant (\ie, typeset by the
<pos> |**\dir|<variant>|{.}| |?>| |*\dir|<dir>).
As a special case an entire <object> is allowed as a <dir> by
starting it with a |*|: |\dir*| is equivalent to |\object|.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Setup:}
|\dir| starts an <object> and passes control to a `finisher' named
|\dir|<variant>|{|<main>|}| otherwise to the one corresponding to an
<empty> <variant>. The kernel ones described here have in common
that they make use of the generic |\straight@| defined
in~\S??[algo.connection].
\DOCMODE(
\xydef@\dir{\hbox\bgroup\xyFN@\dir@i}
\xydef@\dir@i{\ifx *\next \DN@*{\object@}\else \let\next@=\dir@ii \fi \next@}
\xydef@\dir@ii#1#{\dir@{#1}}
\xydef@\dir@#1#2{\DN@{dir#1{#2}}%
\expandafter\let\expandafter\next\csname\codeof\next@\endcsname
\ifx\next\relax \DN@{dir{#2}}%
\expandafter\let\expandafter\next\csname\codeof\next@\endcsname
\ifx\next\relax \DN@{\dir#1{#2}}%
\xyerror@{illegal <dir>: \codeof\next@\space not defined}{}%
\let\next=\no@ \fi\fi \next}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{notes}
\note??=[Dummy]
You may use |\dir{}| for a ``dummy'' directional object (in fact this
is used automatically by |**{}|). This is useful for a uniform
treatment of connections, \eg, making the |?| <pos> able to find a
point on the straight line from $p$ to $c$ without actually
typesetting anything.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Uses an empty droppping, the |\no@@| connection. All the variants
are defined for optimisation reasons and it is also named |\dir{ }|
to allow spurious spaces:
\DOCMODE(
\xydefcsname@{dir{}}{\no@}
\xyletcsnamecsname@{dir0{}}{dir{}}
\xyletcsnamecsname@{dir1{}}{dir{}}
\xyletcsnamecsname@{dir^{}}{dir{}}
\xyletcsnamecsname@{dir_{}}{dir{}}
\xyletcsnamecsname@{dir2{}}{dir{}}
\xyletcsnamecsname@{dir3{}}{dir{}}
\xyletcsnamecsname@{dir{ }}{dir{}}
\xydef@\no@{\egroup \czeroEdge@ \Invisible@false \Hidden@false
\def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\setbox\z@=\copy\voidb@x}\def\Connect@@{\no@@}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[Plain connectors]
The "plain connectors" group contains basic directionals that lend
themself to simple connections.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The bulk of the code is in fact in the description of these. First
each of the three types---lines, dots, and squiggles---then the code
for doubling and tripling.
\paragraph*{Lines:}
A single |\dir{-}| object is a dash in the current direction: build
box with character $C$ of the semidirectional |\xydashfont|; use the
characters natural width $w$ and construct a height/depth from $d =
\abs{\sin(|\Direction|)}|em|$ (where |1em| is the dash length,
\cf~|xydash10.mf|) as follows:
$$
\begin{array}{cccccc}
C & L & R & D & U & "flip if" \\
0\ldots30 & 0 & w & 0 & d & dY \lt 0 \\
31\ldots63 & 0 & w & d & 0 & dY \gt 0 \\
64\ldots95 & 0 & w & d & 0 & dX \lt 0 \\
96\ldots127 & 0 & w & 0 & d & dX \lt 0 \\
\end{array}
$$
where "flip" means shift the box opposite vertically and
horizontally, \ie, $(L,R,D,U) := (R,L,U,D)$, and then lower the box
$D-U$.
"Procedure": (??_[line1])~Compute $d$, (??_[line2])~set $D,U$, and
flip condition, (??_[line3])~build box to get $w,L,R$,
(??_[line4])~dump box that is flipped if condition holds, and
(??_[line5])~finally setup the required parameters properly.
\DOCMODE(
\xydefcsname@{dir1{-}}{\line@}
\xydefcsname@{dir2{-}}{\line@ \double@\xydashh@}
\xydefcsname@{dir3{-}}{\line@ \triple@\xydashh@}
\xyletcsnamecsname@{dir0{-}}{dir{}}
\xyletcsnamecsname@{dir{-}}{dir1{-}}
\xyletcsnamecsname@{dir{=}}{dir2{-}}
\xydef@\line@{\dimen@=\sdY\sinDirection\xydashl@ %?*[line1]
\ifnum\SemiDirectionChar<31 \Dc=\z@ \Uc=\dimen@ \DN@{\dY<\z@}% %?*[line2]
\else\ifnum\SemiDirectionChar<64 \Dc=\dimen@ \Uc=\z@ \DN@{\z@<\dY}%
\else\ifnum\SemiDirectionChar<96 \Dc=\dimen@ \Uc=\z@ \DN@{\dX<\z@}%
\else \Dc=\z@ \Uc=\dimen@ \DN@{\dX<\z@}\fi\fi\fi
\setboxz@h{\line@@}\ht\z@=\Uc \dp\z@=\Dc %?*[line3]
\Lc=\z@ \Rc=\wdz@
\ifdim\next@ \dimen@=\Rc \Rc=\Lc \Lc=\dimen@ %?*[line4]
\dimen@=\Uc \Uc=\Dc \Dc=\dimen@ \advance\dimen@-\Uc
\lower\dimen@\boxz@
\else \boxz@ \fi
\edef\tmp@{\egroup \Uc=\the\Uc \Dc=\the\Dc \Lc=\the\Lc \Rc=\the\Rc}% %?*[line5]
\tmp@
\Edgec={\rectangleEdge}\Invisible@false\Hidden@false
\ifdim\z@<\Uc \def\Upness@{1}\else \def\Upness@{0}\fi
\ifdim\z@<\Lc \def\Leftness@{1}\else \def\Leftness@{0}\fi
\def\Drop@@{\boxz@}\def\Connect@@{\solid@}}
\xydef@\line@@{{\xydashfont\SemiDirectionChar\/}}
\DOCMODE)
\BUG: |\line@| should allow the size of the object to be changed
after typesetting---this should make |\Connect@@| do dashing. Hm.
As mentioned above a dash will `Connect' to make lines by using rules
when strictly horizontal or vertical. This is controlled by enabling
or disabling the test |\ifjusthvtest@| discussed below.
\DOCMODE(
\xydef@\solid@{%
\ifInvisible@ \DN@{\no@@}%
\else \dimen@=\Yc \advance\dimen@-\Yp
\ifjusthvtest@.05pt>\ifdim\dimen@<\z@-\fi\dimen@ \DN@{\solidhrule@}%
\else \dimen@=\Xc \advance\dimen@-\Xp
\ifjusthvtest@.05pt>\ifdim\dimen@<\z@-\fi\dimen@ \DN@{\solidvrule@}%
\else \DN@{\straight@\solidSpread@}\fi\fi\fi
\next@}
\DOCMODE)
Finally, we give the algorithm for `spreading' the dashes along a
solid line: just add an extra dash so they always overlap
(see~\S??[algo.connection] for a proper defintion of the requirements
to spreading).
\DOCMODE(
\xydef@\solidSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
By default \XY-pic will typeset horizontal and vertical |\dir{-}|
connections using \TeX\ rules. Unfortunately rules is the feature of
the DVI format most commonly handled wrong by DVI drivers. Therefore
\XY-pic provides the <decor>ations
%
\begin{defs1}
%
|\NoRules| \cr
|\UseRules| \cr
%
\end{defs1}
\noindent\unskip
%
that will switch the use of such off and on.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
They simply redefine the conditional used to select typesetting
with rules in |\solid@| above:
\DOCMODE(
\xylet@\ifjusthvtest@=\ifdim
\xydef@\NoRules{\let\ifjusthvtest@=\iffalse}
\xydef@\UseRules{\let\ifjusthvtest@=\ifdim}
\DOCMODE)
The actual typesetting essentially means calling |\drop@| to box with
a rule of the appropriate length and with line width set to that of
|\xydashfont| (as stored in |\xydashw@|).
\DOCMODE(
\xydef@\solidvrule@{\no@@{%
\ifdim\Yc<\Yp \dimen@=\Yc \Yc=\Yp \Yp=\dimen@ \advance\Yc-\Dp \advance\Yp\Uc
\else \advance\Yc-\Dc \advance\Yp\Up \fi
\advance\Xc-.5\xydashw@
\setboxz@h{\kern\Xc \vrule width\xydashw@ height\Yc depth-\Yp}%
\ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}}}
\xydef@\solidhrule@{\no@@{%
\ifdim\Xc<\Xp \advance\Xc\Rc \advance\Xp-\Lp
\else \dimen@=\Xc \Xc=\Xp \Xp=\dimen@ \advance\Xc\Rp \advance\Xp-\Lc \fi
\advance\Xp-\Xc \advance\Yc.5\xydashw@ \advance\Yp-.5\xydashw@
\setboxz@h{\kern\Xc \vrule width\Xp height\Yc depth-\Yp}%
\ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}}}
\DOCMODE)
\paragraph*{Dots:}
|\dir{.}| creates a very boring dot when used as an object but
interesting dotted lines when connected with. |\zerodot| should
expand to a zerosized box with a dot (injtilaised to use
|\zero|\-|dotbox@|); the object is built using |\pointlike@| <text>
<spread-dimen> that we will use again later.
\DOCMODE(
\xydef@\zerodot{\copy\zerodotbox@}
\xydefcsname@{dir1{.}}{\point@}
\xydefcsname@{dir2{.}}{\point@ \double@\xydashh@}
\xydefcsname@{dir3{.}}{\point@ \triple@\xydashh@}
\xyletcsnamecsname@{dir0{.}}{dir{}}
\xyletcsnamecsname@{dir{.}}{dir1{.}}
\xyletcsnamecsname@{dir{:}}{dir2{.}}
\xydef@\point@{\pointlike@\zerodot\p@}
\xydef@\pointlike@#1#2{%
\setboxz@h{#1}\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@\egroup
\Invisible@false \Hidden@false \def\Leftness@{.5}\def\Upness@{.5}\ctipEdge@
\def\Drop@@{\boxz@}\def\Connect@@{\straight@{\dottedSpread@{#2}}}}
\DOCMODE)
This is reflected by the rather complicated spreading routine:
`Dotting' is the art of putting zero-sized objects together with
equal distance independent of the chosen direction. So we must
recompute the number of segments $N$ (likely to be very big or
${-}1$) with trigonometrics; using "radius" for the individual dots
this becomes
$$
\begin{array}{lc}
??_[dottedspread1]
& A := \abs{\cos{|\Direction|}}*2*"radius"\\
& B := \abs{\sin{|\Direction|}}*2*"radius"\\
??_[dottedspread2]
& "Filler" := <box with the original filler centered...>\\
??_[dottedspread3]
& |<\dX,\dY>| := |<\dX,\dY>| + |<\sdX|*A|,\sdY|*B|>|\\
& |<|X|,|Y|>| := |<|X|,|Y|>| + |<\sdX|*A/2|,\sdY|*B/2|>|\\
??_[dottedspread4]
& N := \floor{"if"~\abs{dX}\gt\abs{dY}
~"then" \abs{dX}/A else \abs{dY}/B} + 1
\end{array}
$$
as realised below:
\DOCMODE(
\xydef@\dottedSpread@#1{\setupDirection@ %?*[dottedspread1]
\dimen@=#1\relax \dimen@=2\dimen@
\A@=\sdX\cosDirection\dimen@ \B@=\sdY\sinDirection\dimen@
\global\setbox\lastobjectbox@=\hbox to\A@{\hss %?*[dottedspread2]
\kern.5\A@\box\lastobjectbox@\kern.5\A@\hss}%
\dp\lastobjectbox@=.5\B@ \ht\lastobjectbox@=.5\B@
\advance\dX\sdX\A@ \advance\dY\sdY\B@ %?*[dottedspread3]
\advance\Xc\sdX.5\A@ \advance\Yc\sdY.5\B@
\ifdim\sdY\dY<\sdX\dX \dimen@=\sdX\dX %?*[dottedspread4]
\ifdim\A@=\z@\else \divide\dimen@\A@ \fi \count@@=\dimen@
\else\ifdim\z@=\sdY\dY\else
\dimen@=\sdY\dY \ifdim\B@=\z@\else \divide\dimen@\B@ \fi \count@@=\dimen@
\fi\fi \advance\count@@\@ne}
\DOCMODE)
\paragraph*{Squiggles:}
These are just a lot of box maneuvering using the directional
characters of |\xybsqlfont| (see~|xybsql10.mf| for details):
\DOCMODE(
\xydefcsname@{dir1{~}}{\squiggle@}
\xydefcsname@{dir2{~}}{\squiggle@ \double@\xybsqlh@}
\xydefcsname@{dir3{~}}{\squiggle@ \triple@\xybsqlh@}
\xyletcsnamecsname@{dir0{~}}{dir{}}
\xyletcsnamecsname@{dir{~}}{dir1{~}}
\xydef@\squiggle@{\xybsqlfont
\dimen@=\sdX\cosDirection\xybsqll@ \advance\dimen@.1\p@
\dimen@ii=\sdY\sinDirection\xybsqll@
\kern\dimen@\squiggle@@
\edef\tmp@{\egroup \Uc=\the\dimen@ii \Lc=\the\dimen@}\tmp@
\wdz@=2\Lc \Rc=\Lc \ht\z@=\Uc \Dc=\Uc \dp\z@=\Uc \Edgec={\rectangleEdge}%
\Invisible@false \Hidden@false \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@\squiggledSpread@}}
\xydef@\squiggle@@{\DirectionChar \count@=\DirectionChar
\advance\count@-64 \ifnum\count@<\z@ \advance\count@128 \fi \char\count@}
\DOCMODE)
The interesting bit is that they spread by not spreading, \ie, by
centering between the endpoints---this means
$$
\begin{array}{ll}
X := X - d/2, dX := dX - d
&\hbox{where}~ d = |\sdX|(\abs{dX} - N*A + |.1pt|)\\
Y := Y - d/2, dY := dY - d
&\hbox{where}~ d = |\sdY|(\abs{dY} - N*B + |.1pt|)\\
\end{array}
$$
\DOCMODE(
\xydef@\squiggledSpread@{%
\dimen@=\dX \advance\dimen@-\sdX\count@@\A@ \advance\dimen@\sdX.3\p@
\advance\Xc-.5\dimen@ \advance\dX-\dimen@
\dimen@=\dY \advance\dimen@-\sdY\count@@\B@ \advance\dimen@\sdY.3\p@
\advance\Yc-.5\dimen@ \advance\dY-\dimen@}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Double and triple directionals:}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
As can be seen by the last two columns, these (and most of the other
connectors) also exist in double and triple versions with a |2| or a
|3| prepended to the name. For convenience |\dir{=}| and |\dir{:}|
are synonyms for |\dir2{-}| and |\dir2{.}|, respectively; similarly
|\dir{==}| is a synonym for |\dir2{--}|.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This is very simple, really: |\double@| and |\triple@| do the work by
redefining the |\Drop@@| method to do its job twice and thrice.
\DOCMODE(
\xydef@\double@#1{\edef\Drop@@{\dimen@=#1\relax
\dimen@=.5\dimen@ \A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@
\setbox2=\hbox{\kern\A@\raise\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 %
\setbox2=\hbox{\kern-\A@\raise-\B@\boxz@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 }}
\xydef@\triple@#1{\edef\Drop@@{\dimen@=#1\relax
\A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@
\setbox2=\hbox{\kern\A@\raise\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 %
\setbox2=\hbox{\kern-\A@\raise-\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 %
\dp\z@=\z@ \ht\z@=\z@ \wdz@=\z@ \boxz@}}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Dashing directionals:}
First traditional dashing:
\DOCMODE(
\xydefcsname@{dir1{--}}{\dash@}
\xydefcsname@{dir2{--}}{\dash@ \double@\xydashh@}
\xydefcsname@{dir3{--}}{\dash@ \triple@\xydashh@}
\xyletcsnamecsname@{dir0{--}}{dir{}}
\xyletcsnamecsname@{dir{--}}{dir1{--}}
\xyletcsnamecsname@{dir{==}}{dir2{--}}
\xydef@\dash@{\line@ \wdz@=2\wdz@ \ht\z@=2\ht\z@ \dp\z@=2\dp\z@
\multiply\Dc\tw@ \multiply\Uc\tw@ \multiply\Lc\tw@ \multiply\Rc\tw@
\def\Connect@@{\straight@\dashedSpread@}}
\DOCMODE)
Since the dashes should reach the endpoints we do this:
$$
\begin{array}{l}
"if"~ N\gt 0 ~"then"~ N := N+1\\
dX := dX + d/2 ~"where"~ d = |\sdX|A\\
dY := dY + d/2 ~"where"~ d = |\sdY|B\\
"if"~ dX\gt 0 ~"then"~ X := X + A/2\\
Y := Y + |\sdY|A/2\\
\end{array}
$$
\DOCMODE(
\xydef@\dashedSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi
\advance\dX\sdX.5\A@ \advance\dY\sdY.5\B@
\ifdim\z@<\dX \advance\Xc.5\A@ \fi \advance\Yc\sdY.5\B@}
\DOCMODE)
Dashed dashing of squiggled lines are simpler since squiggles are
symmetric:
\DOCMODE(
\xydefcsname@{dir1{~~}}{\dashsquiggle@}
\xydefcsname@{dir2{~~}}{\dashsquiggle@ \double@\xybsqlh@}
\xydefcsname@{dir3{~~}}{\dashsquiggle@ \triple@\xybsqlh@}
\xyletcsnamecsname@{dir0{~~}}{dir{}}
\xyletcsnamecsname@{dir{~~}}{dir1{~~}}
\xydef@\dashsquiggle@{\squiggle@
\multiply\Dc\tw@ \multiply\Uc\tw@ \multiply\Lc\tw@ \multiply\Rc\tw@
\dimen@=\Lc \advance\dimen@\Rc \wdz@=\dimen@ \ht\z@=\Uc \dp\z@=\Dc
\def\Connect@@{\straight@\dashsquiggledSpread@}}
\DOCMODE)
The spreading of squiggles is similarly simpler: we just shave $1/4$
squiggle size of each end of the conection in order to eliminate the
blank space at both ends:
\DOCMODE(
\xydef@\dashsquiggledSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi
\advance\Xc.5\A@ \advance\dX.5\A@ \advance\Yc.25\B@ \advance\dY.5\B@}
\DOCMODE)
Finally ``dashed dotting'' synonyms:
\DOCMODE(
\xyletcsnamecsname@{dir1{..}}{dir{.}}
\xyletcsnamecsname@{dir2{..}}{dir2{.}}
\xyletcsnamecsname@{dir3{..}}{dir3{.}}
\xyletcsnamecsname@{dir{..}}{dir1{.}}
\xyletcsnamecsname@{dir{::}}{dir2{.}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[Plain tips]
The group of "plain tips" contains basic objects that are useful as
markers and arrowheads making connections, so each is shown at the
end of a dotted connection of the appropriate kind.
They may also be used as connectors and will build dotted
connections. \eg, |**\dir{>}| typesets
$$
\xy 0*++{}; (10,3)*++{} **\dir{>} \endxy
$$
\begin{exercise}
Typeset the following two $+$s and a tilted square:
\begin{code}
$$\xy
*{+}; p+(6,3)*{+} **{} ?(1)
*\dir{-} *!/-5pt/^\dir{-}
*^\dir{-} *!/^-5pt/\dir{-}
\endxy$$
\end{code}
\docode
%
"Hint": the dash created by |\dir{-}| has the length |5pt|.
%
\answercode
\answertext{One way is}
\answertext\displaycode
\answertext{Thus we first create the two $+$s as $p$ and $c$ and connect them
with the dummy connection |**{}| to setup the direction parameters.
Then we move `on top of $c$' with |?(1)| and position the four sides
of the square using |^| and |_| for local direction changes and
|/|<dimen>|/| for skewing the resulting object by moving its
reference point in the opposite direction.}%
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\DOCMODE(
\xylet@\ctipEdge@=\czeroEdge@
\DOCMODE)
\TODO: Change tips to have a tiny size of 2sp which may be taken as
an indication that it is a tip (this can be used by some features,
\eg, `arrow').
\paragraph*{Arrow heads:}
The ones intended for single connections are just characters from
|\xyatipfont| and |\xybtipfont|.
\DOCMODE(
\xydefcsname@{dir1{>}}{\tip@}
\xydefcsname@{dir^{>}}{\atip@}
\xydefcsname@{dir_{>}}{\btip@}
\xyletcsnamecsname@{dir0{>}}{dir{}}
\xyletcsnamecsname@{dir{>}}{dir1{>}}
\xydefcsname@{dir1{<}}{\reverseDirection@\tip@}
\xydefcsname@{dir^{<}}{\reverseDirection@\btip@}
\xydefcsname@{dir_{<}}{\reverseDirection@\atip@}
\xyletcsnamecsname@{dir0{<}}{dir{}}
\xyletcsnamecsname@{dir{<}}{dir1{<}}
\xydef@\tip@{\tip@x\tip@@}
\xydef@\atip@{\tip@x\atip@@}
\xydef@\btip@{\tip@x\btip@@}
\xydef@\tip@x#1{#1\egroup
\ctipEdge@ \Invisible@false \Hidden@false \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}}
\xydef@\tip@@{\atip@@\btip@@}
\xydef@\atip@@{\xyatipfont\DirectionChar}
\xydef@\btip@@{\xybtipfont\DirectionChar}
\DOCMODE)
Double and triple tips are realised by taking the two halfs and
`wringing them apart'; as the naming indicates they are meant to be
put at the end of |2|- and |3|-connections. This is currently done
the slightly hacky (but efficient) way of adding directly to
|\DirectionChar|; maybe this should be using |\vDirection@|?
\DOCMODE(
\xydefcsname@{dir2{>}}{\Tip@}
\xydefcsname@{dir2{<}}{\reverseDirection@\Tip@}
\xydef@\Tip@{\kern2.5pt \vrule height2.5pt depth2.5pt width\z@
\Tip@@ \kern2.5pt \egroup
\Uc=2.5pt \Dc=2.5pt \Lc=2.5pt \Rc=2.5pt \Edgec={\circleEdge}%
\Invisible@false \Hidden@false \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}}
\xydef@\Tip@@{\count@=\DirectionChar
\advance\count@-4 \ifnum\count@<\z@ \advance\count@128 \fi
\xyatipfont\char\count@
\advance\count@ 8 \ifnum127<\count@ \advance\count@-128 \fi
\xybtipfont\char\count@}
\xydefcsname@{dir3{>}}{\Ttip@}
\xydefcsname@{dir3{<}}{\reverseDirection@\Ttip@}
\xydef@\Ttip@{\kern3.2pt \vrule height3.2pt depth3.2pt width\z@
\Ttip@@ \kern3.2pt \egroup
\Uc=3.2pt \Dc=3.2pt \Lc=3.2pt \Rc=3.2pt \Edgec={\circleEdge}%
\Invisible@false \Hidden@false \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}}
\xydef@\Ttip@@{%
\setboxz@h\bgroup\reverseDirection@\line@ \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@
\kern-\Lc \boxz@ \kern\Lc
{\vDirection@(1,-.31)\xydashl@ \xyatipfont\char\DirectionChar}%
{\vDirection@(1,+.31)\xydashl@ \xybtipfont\char\DirectionChar}}
\DOCMODE)
\paragraph*{Stopper:}
|\dir{||}| makes a `stopper' using just the appropriate |\xydashfont|
character rotated $90^\circ$ and centered; the |^| and |_| variants
are just shifted appropriately and two are used to make the |2| and
|3| variants longer.
\DOCMODE(
\xydefcsname@{dir1{|}}{\stopper@}
\xydefcsname@{dir^{|}}{\aboveDirection@\xydashl@
\shiftdir@\line@\z@ \pointlike@{}\xydashh@}
\xydefcsname@{dir_{|}}{\belowDirection@\xydashl@
\shiftdir@\line@\z@ \pointlike@{}\xydashh@}
\xydefcsname@{dir2{|}}{\stopper@ \double@\xydashh@}
\xydefcsname@{dir3{|}}{\stopper@ \double@{2\xydashh@}}
\xyletcsnamecsname@{dir0{|}}{dir{}}
\xyletcsnamecsname@{dir{|}}{dir1{|}}
\xydef@\stopper@{\tip@x\stopper@@}
\xydef@\stopper@@{\setboxz@h{\count@=\SemiDirectionChar \advance\count@64 %
\ifnum127<\count@ \advance\count@-128 \fi \xydashfont\char\count@\/}%
\setboxz@h{\kern-.5\wdz@ \dimen@=\sdY\cosDirection\xydashl@
\ifnum\SemiDirectionChar=95 \dimen@=\sdX\sdY\dimen@ \fi
\raise.5\dimen@\boxz@}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\DOCMODE)
\paragraph*{Hooks:}
These are halfcircles opening towards or opposite |\Direction| and
fastened by their center or either endpoint. Build by lots of box
manipulation with the |\xybsqlfont| quarter circles\dots\smiley
\DOCMODE(
\xydefcsname@{dir1{(}}{\hook@}
\xydefcsname@{dir^{(}}{\ahook@}
\xydefcsname@{dir_{(}}{\bhook@}
\xyletcsnamecsname@{dir0{(}}{dir{}}
\xyletcsnamecsname@{dir{(}}{dir1{(}}
\xydefcsname@{dir1{)}}{\reverseDirection@\hook@}
\xydefcsname@{dir^{)}}{\reverseDirection@\bhook@}
\xydefcsname@{dir_{)}}{\reverseDirection@\ahook@}
\xyletcsnamecsname@{dir0{)}}{dir{}}
\xyletcsnamecsname@{dir{)}}{dir1{)}}
\xydef@\hook@{\tip@x\hook@@}
\xydef@\hook@@{\setboxz@h{\xybsqlfont
\vDirection@(1,-1){.707107\xybsqll@}%
\hbox{\DirectionChar
\kern-\dY\raise\dX\hbox{\count@=\DirectionChar \advance\count@-32 %
\ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\xydef@\ahook@{\tip@x\ahook@@}
\xydef@\ahook@@{\setboxz@h{\xybsqlfont
\vDirection@(1,-1){.707107\xybsqll@}\kern-\dX
\lower\dY\hbox{\DirectionChar
\kern-\dY\raise\dX\hbox{\count@=\DirectionChar \advance\count@-32 %
\ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\xydef@\bhook@{\tip@x\bhook@@}
\xydef@\bhook@@{\setboxz@h{\xybsqlfont
\vDirection@(-1,-1){.707107\xybsqll@}\DirectionChar
\kern\dX\raise\dY\hbox{\count@=\DirectionChar \advance\count@-96 %
\ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\DOCMODE)
\paragraph*{Quarter turns:}
These are quarter circles fastened by their start or end point in
|\Direction|. Build by box manipulation of the |\xybsqlfont| quarter
circles. The intention is that the |`'| directionals are half the
corresponding |()| directional.
\DOCMODE(
\xydefcsname@{dir^{'}}{\reverseDirection@\bturn@}
\xydefcsname@{dir_{'}}{\reverseDirection@\aturn@}
\xydefcsname@{dir^{`}}{\aturn@}
\xydefcsname@{dir_{`}}{\bturn@}
\xydef@\aturn@{\tip@x\aturn@@}
\xydef@\aturn@@{\setboxz@h{\xybsqlfont
\vDirection@(1,-1){.707107\xybsqll@}\kern-\dX
\lower\dY\hbox{\DirectionChar}}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\xydef@\bturn@{\tip@x\bturn@@}
\xydef@\bturn@@{\setboxz@h{\xybsqlfont
\vDirection@(-1,-1){.707107\xybsqll@}\DirectionChar}%
\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\note??=[Constructed tips]
These tips are combinations of the plain tips provided for
convenience (and optimised for efficiency). New ones can be
constructed using |\composite| and by declarations of the form
%
\begin{defs1}
%
|\newdir| <dir> |{|<composite>|}|\cr
%
\end{defs1}
\noindent\unskip
%
which defines |\dir|<dir> as the <composite> (see note~??[composite
object box] for the details).
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|\newdir| is simple:
\DOCMODE(
\xydef@\newdir#1#{\newdir@{#1}}
\xydef@\newdir@#1#2#3{\xydefcsname@{dir#1{#2}}{\composite@{}{#3}}}
\DOCMODE)
Then the somewhat more efficient |\shiftdir@| used internally for
moving a tip in the current direction---it does so by making a local
hbox within which the argument tip is constructed and subsequently
shifted and made of zero size. Use as
$$
|\shiftdir@|<tip@><dimen><tip@>
$$
where <tip@> means a tip command without the leading |\hbox{|.
\DOCMODE(
\xydef@\shiftdir@#1#2{%
\setbox\z@=\hbox\bgroup#1\relax
\setboxz@h{\dimen@ii=#2\relax
\dimen@=-\cosDirection\dimen@ii \advance\dimen@-\Lc
\kern\dimen@ \lower\sinDirection\dimen@ii\boxz@}%
\wdz@\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@}
\DOCMODE)
Then the tips, with the |\tipjot@| hook allowing changing the spacing
of tips used for single lines.
\DOCMODE(
\xylet@\tipjot@=\jot
\xydefcsname@{dir1{>>}}{\shiftdir@\tip@\tipjot@ \tip@}
\xydefcsname@{dir^{>>}}{\shiftdir@\atip@\tipjot@ \atip@}
\xydefcsname@{dir_{>>}}{\shiftdir@\btip@\tipjot@ \btip@}
\xydefcsname@{dir2{>>}}{\composite@{}{h!/\tipjot@/\dir2{>}*\dir2{>}}}
\xydefcsname@{dir3{>>}}{\composite@{}{h!/\tipjot@/\dir3{>}*\dir3{>}}}
\xyletcsnamecsname@{dir0{>>}}{dir{}}
\xyletcsnamecsname@{dir{>>}}{dir1{>>}}
\xydefcsname@{dir1{<<}}{\reverseDirection@ \shiftdir@\tip@\tipjot@ \tip@}
\xydefcsname@{dir^{<<}}{\reverseDirection@ \shiftdir@\btip@\tipjot@ \btip@}
\xydefcsname@{dir_{<<}}{\reverseDirection@ \shiftdir@\atip@\tipjot@ \atip@}
\xydefcsname@{dir2{<<}}{\composite@{}{h!/-\tipjot@/\dir2{<}*\dir2{<}}}
\xydefcsname@{dir3{<<}}{\composite@{}{h!/-\tipjot@/\dir3{<}*\dir3{<}}}
\xyletcsnamecsname@{dir0{<<}}{dir{}}
\xyletcsnamecsname@{dir{<<}}{dir1{<<}}
\xydefcsname@{dir{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@
\pointlike@{}\jot}
\xydefcsname@{dir^{||}}{\shiftdir@{\aboveDirection@\xydashl@\line@}\xydashh@
\shiftdir@{\aboveDirection@\xydashl@\line@}\z@ \pointlike@{}\jot}
\xydefcsname@{dir_{||}}{\shiftdir@{\belowDirection@\xydashl@\line@}\xydashh@
\shiftdir@{\belowDirection@\xydashl@\line@}\z@ \pointlike@{}\jot}
\xydefcsname@{dir2{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@
\pointlike@{}\jot \double@\xydashh@}
\xydefcsname@{dir3{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@
\pointlike@{}\jot \double@{2\xydashh@}}
\xydefcsname@{dir{>|}}{\shiftdir@\stopper@\z@ \tip@}
\xydefcsname@{dir{>>|}}{\shiftdir@\stopper@\z@ \shiftdir@\tip@\tipjot@ \tip@}
\xydefcsname@{dir{|<}}{\reverseDirection@ \shiftdir@\stopper@\z@ \tip@}
\xydefcsname@{dir{|<<}}{\reverseDirection@
\shiftdir@\stopper@\z@ \shiftdir@\tip@\tipjot@ \tip@}
\xydefcsname@{dir{|-}}{\shiftdir@\stopper@\z@
\shiftdir@\line@\z@ \pointlike@{}\jot}
\xydefcsname@{dir^{|-}}{\shiftdir@{\aboveDirection@\xydashl@ \line@}\z@
\shiftdir@\line@\z@ \pointlike@{}\jot}
\xydefcsname@{dir_{|-}}{\shiftdir@{\belowDirection@\xydashl@ \line@}\z@
\shiftdir@\line@\z@ \pointlike@{}\jot}
\xydefcsname@{dir2{|-}}{\shiftdir@\stopper@\z@
\shiftdir@\line@\z@ \pointlike@{}\jot \double@\xydashh@}
\xydefcsname@{dir3{|-}}{\shiftdir@\stopper@\z@
\shiftdir@\line@\z@ \pointlike@{}\jot \triple@\xydashh@}
%\xydefcsname@{dir^{|-}}{\composite@{}{\dir^{|}*\dir{-}}}
%\xydefcsname@{dir_{|-}}{\shiftdir@{\belowDirection@\xydashl@\line@}\z@\line@}
%\xydefcsname@{dir2{|-}}{\shiftdir@\stopper@\z@ \line@ \double@\xydashh@}
%\xydefcsname@{dir3{|-}}{\shiftdir@\stopper@\z@ \line@ \triple@\xydashh@}
\xyletcsnamecsname@{dir0{|=}}{dir{}}
\xyletcsnamecsname@{dir{|=}}{dir2{|-}}
\xydefcsname@{dir{+}}{%
\DN@##1{\composite@{}{##10\dir{|}*!C##10\dir{-}}}\addEQ@\next@}
\xydefcsname@{dir{x}}{\vDirection@(1,1)\jot
\DN@##1{\composite@{}{##10\dir{|}*!C##10\dir{-}}}\addEQ@\next@}
\xydefcsname@{dir{/}}{\vDirection@(1,-.3)\jot \stopper@}
\xydefcsname@{dir{*}}{\solidpoint@}
\xydef@\solidpoint@{%
\pointlike@{\kern-1.8pt\lower1.8pt\hbox{$\scriptstyle\bullet$}}\jot}
\xydefcsname@{dir{o}}{\hollowpoint@}
\xydef@\hollowpoint@{%
\pointlike@{\kern-1.8pt\lower1.8pt\hbox{$\scriptstyle\circ$}}\jot}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{notes}
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Circle segments}
??=[objectlib.circles]
\DOCMODE(
\message{circles,}
\DOCMODE)
Circle <object>s are round and typeset a segment of the circle
centered at the reference point. The syntax of circles is described
in figure~??[f.cir] with explanations below.
\begin{figure*}
\vss
\begin{syntax}
%
\multispan3|\cir| <radius> |{| <cir> |}|\hfil
& <cir>cle segment with <radius>
\cr
\noalign{\nobreak\smallskip\nobreak\hrule\nobreak\smallskip\nobreak}
%
??w![<radius>]
&\iss & <empty>
& use $R_c$ as the radius
\cr
&\orr & <vector>
& use $X$ of the <vector> as radius
\cr
\noalign{\smallbreak}
%
??w![<cir>]
&\iss & <empty>
& full circle of <radius>
\cr
&\orr & <diag> <orient> <diag>
& partial circle from first <diag>onal through to the
second <diag>onal in the <orient>ation
\cr
\noalign{\smallbreak}
%
??w![<orient>]
&\iss & |^|
& anticlockwise
\cr
&\orr & |_|
& clockwise
\cr
\end{syntax}
\caption{\protect<cir>cles.}
??=[f.cir]
\vfill
\end{figure*}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The |\cir| command is the hub: it parses the optional <radius> (to
|\R@|, default from $R_c$) and |{|<cir>|}|, bailing out with a
|\zerodot| if the radius is to small:
\DOCMODE(
\xydef@\cir#1#{\hbox\bgroup
\afterVECTORorEMPTY{\xy@@{\R@=\Xc}\cir@}{\xy@@{\R@=\Rc}\cir@}#1@}
\xydef@\cir@#1@#2{%
\DN@{#1}\ifx\next@\empty\else \xyerror@{illegal circle <radius>: must be
<vector> or <empty>}{}\fi
\afterCIRorDIAG{\xyFN@\cir@cir}{\xyFN@\cir@diag}#2@}
\DOCMODE)
The code to actually typeset the <cir> just parsed starts by checking
that the <cir> was immediately followed by the |@| we put there in
|\cir|:
\DOCMODE(
\xydef@\cir@cir{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\cir@cir}%gobble spaces
\else \ifx @\next \DN@ @{\cir@i}%
\else \xyerror@{illegal <cir>: must have form <diag><orient><diag> or
<empty>}{}%
\fi\fi \next@}
\DOCMODE)
Similarly when an <empty> one was given---the parser will recognise
this as a <diag> but we hack that here:
\DOCMODE(
\xydef@\cir@diag{%
\DN@{\xyerror@{illegal <cir>: must have form <diag><orient><diag> or
<empty>}{}}%
\ifx @\next \ifnum\count@=8 %
\DN@ @{\def\CIRin@@{0}\def\CIRorient@@{\CIRfull@}\def\CIRout@@{7}\cir@i}%
\fi\fi \next@}
\DOCMODE)
\dots and then use the constructed methods to build it:
\DOCMODE(
\xydef@\cir@i{%
\ifnum\CIRin@@=8 \xyerror@{incomplete <cir> specification}{%
The <cir> you specified as <diag><orient><diag> is not sufficiently specific.}%
\def\CIRin@@{0}\fi
\ifdim\R@<.5\p@ \R@=\z@ \zerodot
\else \CIRorient@@ \cirbuild@ \fi
\Lc=\R@ \Rc=\R@ \Dc=\R@ \Uc=\R@ \def\Leftness@{.5}\def\Upness@{.5}%
\def\Drop@@{\boxz@}\def\Connect@@{\straight@\relax}\Edgec={\circleEdge}%
\OBJECT@x}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{Parsing:}
The |\afterCIRorDIAG| parser handles the parsing: it either
%
\begin{itemize}
\item
parses the <cir> and sets "in", "orient", and "out", and passes
control to the first argument continuation, or
\item
parses the single <diag> specified, store it in |\count@| (as |8| if
an <empty> one given), and pass control to the second continuation
argument,
\end{itemize}
%
where the <diag> internal representation number of note~??[diagonal]
of is used. An <empty> circle is treated as an <empty> diagonal;
specifying an <empty> first <diag> of a <cir> is equivalent to using
the value of the "in" method at call time.
The parser is very simple, setting methods stored in the usual
|@@|-terminated control sequences (\TODO: Rename all non-method
control sequences that end in |@@|\dots to use |@|<romannumeral>
suffixes\dots):
\DOCMODE(
\xydef@\CIRin@@{3}
\xydef@\CIRout@@{3}
\xylet@\CIRorient@@=\empty
\xydef@\afterCIRorDIAG#1#2{\def\afterCIR@{#1}\def\afterCIRDIAG@{#2}\xyFN@\CIR@}
\xylet@\afterCIR@=\empty
\xylet@\afterCIRDIAG@=\empty
\xydef@\CIR@{\count@=8 \afterDIAG{\edef\CIRin@@{\the\count@}\xyFN@\CIR@@}}
\xydef@\CIR@@{%
\ifx \space@\next \expandafter\DN@\space{\xyFN@\CIR@@}%gobble spaces
\else\ifx ^\next
\DN@ ^{\def\CIRorient@@{\CIRacw@}%
\afterDIAG{\edef\CIRout@@{\the\count@}\afterCIR@}}%
\else\ifx _\next
\DN@_{\def\CIRorient@@{\CIRcw@}%
\afterDIAG{\edef\CIRout@@{\the\count@}\afterCIR@}}%
\else
\DN@{\def\CIRorient@@{\relax}\afterCIRDIAG@}%
\fi\fi\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The default is to generate a "full circle" with the specified radius,
\eg,
$$
\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0}
\begin{array}{ccc}
|\xy*\cir<4pt>{}\endxy|
&\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{}\endxy}
\cr
|\xy*{M}*\cir{}\endxy|
&\hbox{---}& \quotesmash{\xy*{M}*\cir{}\endxy}
\end{array}
$$
All the other circle segments are subsets of this and have the shape
that the full circle outlines.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Finally we present the "orient" methods. They use these `internal
methods' to actually draw the circles
\DOCMODE(
\xylet@\CIRtest@@=\relax
\xydef@\CIRlo@@{0}
\xydef@\CIRhi@@{0}
\DOCMODE)
Below we call them "lo", "hi", and "test"; the first two are coded as
described in note ??[diagonal] and the last takes two arguments: a
dimension and something to do if the test succeeds. |\count@@| and
|\count@| should be set to "in" and "out" internally as well in case
|\cirbuild@| and friends below should be used.
The dummy "orient" used for simple circles is the simplest:
\DOCMODE(
\xydef@\CIRfull@{\def\CIRtest@@##1##2{##2}}
\DOCMODE)
The kernel |\cirbuild@| builds the actual <object> using characters
from the |\xycircfont| assumed coded like |xycirc10.mf|:
|\cirrestrict@@| choses a group and adjusts the radius |\R@| to fit it
exactly. The group is multiplied by 8 to get the group character
offset [|\count@|].
\DOCMODE(
\xydef@\cirbuild@{\cirrestrict@@ \multiply\count@8 %
\circhar@0\circhar@7\kern\dimen@
\circhar@1\circhar@6\kern\dimen@
\circhar@2\circhar@5\kern\dimen@
\circhar@3\circhar@4\kern\dimen@}
\xydef@\circhar@#1{%
\setboxz@h{\circhar@@{#1}}\dimen@=\wdz@ \wdz@=\z@ \ht\z@=\R@ \dp\z@=\R@
\CIRtest@@#1{\boxz@}\setbox\z@=\copy\voidb@x}
\xydef@\circhar@@#1{{\xycircfont \advance\count@#1\relax \char\count@}}
\DOCMODE)
|\cirrestrict@@| computes the group $g$ [|\count@|] of circle segments
to use from the radius $r$ [|\R@|] using the formula (the reverse of
the one in |xycirc10.mf|)
$$
\def\arraystretch{1}
g = \left\{ \begin{array}{ll}
\floor{r\over1|pt|}-1 &\text{if}~ 1|pt|\le r\lt 8|pt|\\
\floor{r\over2|pt|}+3 &\text{if}~ 8|pt|\le r\lt 16|pt|\\
\floor{r\over4|pt|}+7 &\text{if}~16|pt|\le r\lt 32|pt|\\
15 &\text{if}~32|pt|\le r \end{array}
\right.
$$
(where we know from |\cir@i| that $r\ge\frac12|pt|$), and then
adjusts the radius to be exactly the one chosen through the use of
group $g$ using the formula in |xycirc10.mf|\dots this is necessary
because of the restriction on |tfm| files that they can only have 15
different nonzero heights and depths. Subsequent calls to
|\cirrestrict@@| should compute the same values.
\DOCMODE(
\xydef@\cirrestrict@@{\dimen@=\R@
\ifdim\R@<8pt \count@=\dimen@ \divide\count@\p@ \advance\count@\m@ne
\else\ifdim\R@<16pt \count@=\dimen@
\dimen@=2\p@ \divide\count@\dimen@ \advance\count@3 %
\else\ifdim\R@<32pt \count@=\dimen@
\dimen@=4\p@ \divide\count@\dimen@ \advance\count@7 %
\else \count@=15 \fi\fi\fi
\R@=\p@
\ifnum\count@<8 \multiply\R@\count@ \advance\R@\p@
\else\ifnum\count@<12 \multiply\R@\count@ \multiply\R@\tw@ \advance\R@-6\p@
\else\ifnum\count@<16 \multiply\R@\count@ \multiply\R@ 4 \advance\R@-28\p@
\else \multiply\R@ 32 \fi\fi\fi}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
"Partial circle segments" with <orient>ation are the part of the full
circle that starts with a tangent vector in the direction of the
first <diag>onal (see note~??[diagonal]) and ends with a tangent
vector in the direction of the other <diag>onal after a clockwise
(for |_|) or anticlockwise (for |^|) turn, \eg,
$$
\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0}
\begin{array}{ccc}
|\xy*\cir<4pt>{l^r}\endxy|
&\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{l^r}\endxy}
\\
|\xy*\cir<4pt>{l_r}\endxy|
&\hbox{---}& \quotesmash{\xy*\cir<4pt>{l_r}\endxy}
\\
|\xy*\cir<4pt>{dl^u}\endxy|
&\hbox{---}& \quotesmash{\xy*\cir<4pt>{dl^u}\endxy}
\\
|\xy*\cir<4pt>{dl_u}\endxy|
&\hbox{---}& \quotesmash{\xy*\cir<4pt>{dl_u}\endxy}
\\
|\xy*+{M}*\cir{dr_ur}\endxy|
&\hbox{---}& \quotesmash{\xy*+{M}*\cir{dr_ur}\endxy}
\end{array}
$$
If the same <diag> is given twice then nothing is typeset, \eg,
$$
\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0}
\begin{array}{ccc}
|\xy*\cir<4pt>{u^u}\endxy|
&\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{u^u}\endxy}
\end{array}
$$
Special care is taken to setup the <diag>onal defaults:
%
\begin{itemize}
\item
After |^| the default is the diagonal $90^\circ$ anticlockwise from
the one before the |^|.
\item
After |_| the default is the diagonal $90^\circ$ clockwise from the
one before the |_|.
\end{itemize}
%
The <diag> before |^| or |_| is required for |\cir| <objects>.
\begin{exercise}
Typeset the following shaded circle with radius |5pt|:
%
\begin{code}
$$\xy
*\cir<5pt>{}
*!<-.2pt,.2pt>\cir<5pt>{dr^ul}
*!<-.4pt,.4pt>\cir<5pt>{dr^ul}
*!<-.6pt,.6pt>\cir<5pt>{dr^ul}
\endxy$$
\end{code}
\docode
%
\answertext{One way is to add extra half circles skewed such that they create
the illusion of a shade:}
\answercode
\answertext\displaycode
\end{exercise}
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
These two macros implement the defaults and setup of "lo" and "hi"
for anticlockwise and clockwise segments. Here is what they set:
$$
\begin{array}{\otherbar c\otherbar cc\otherbar l\otherbar}
\hline
??w![<cir>] & "lo" & "hi" & "test"(s) \\
\hline
d_1|^|d_2, d_1\le d_2 & d_1 -_8 1 & d_2 -_8 1 & {"lo"\le s}\wedge{s\lt "hi"}\\
d_1|^|d_2, d_1\gt d_2 & d_2 -_8 1 & d_1 -_8 1 & {s \lt"lo"} \vee {"hi"\le s}\\
d_1|_|d_2, d_1\lt d_2 & d_1 +_8 3 & d_2 +_8 3 & {s \lt"lo"} \vee {"hi"\le s}\\
d_1|_|d_2, d_1\ge d_2 & d_2 +_8 3 & d_1 +_8 3 & {"lo"\le s}\wedge{s\lt "hi"}\\
\hline
\end{array}
$$
where $+_8$ and $-_8$ are $+$ and $-$ modulo 8; $d_1$ and $d_2$ are
in |\count@@| and |\count@|, respectively.
\DOCMODE(
\xydef@\CIRacw@{\count@@=\CIRin@@ \count@=\CIRout@@
\ifnum\count@=8 \count@=\count@@
\ifnum\count@<6 \advance\count@\tw@ \else \advance\count@-6 \fi \fi
\ifnum\count@@<\@ne \advance\count@@7 \else \advance\count@@\m@ne \fi
\ifnum\count@<\@ne \advance\count@7 \else \advance\count@\m@ne \fi
\ifnum\count@@>\count@ \let\CIRtest@@=\CIRtest@outside
\edef\CIRlo@@{\the\count@}\edef\CIRhi@@{\the\count@@}%
\else \let\CIRtest@@=\CIRtest@inside
\edef\CIRlo@@{\the\count@@}\edef\CIRhi@@{\the\count@}%
\fi}
\xydef@\CIRcw@{\count@@=\CIRin@@ \count@=\CIRout@@
\ifnum\count@=8 \count@=\count@@
\ifnum\count@>\@ne \advance\count@-\tw@ \else \advance\count@6 \fi \fi
\ifnum\count@@<5 \advance\count@@\thr@@ \else \advance\count@@-5 \fi
\ifnum\count@<5 \advance\count@\thr@@ \else \advance\count@-5 \fi
\ifnum\count@@<\count@ \let\CIRtest@@=\CIRtest@outside
\edef\CIRlo@@{\the\count@@}\edef\CIRhi@@{\the\count@}%
\else \let\CIRtest@@=\CIRtest@inside
\edef\CIRlo@@{\the\count@}\edef\CIRhi@@{\the\count@@}%
\fi}
\xydef@\CIRtest@inside#1#2{\let\next@=\relax
\ifnum\CIRlo@@>#1\else \ifnum#1<\CIRhi@@\DN@{#2}\fi\fi \next@}
\xydef@\CIRtest@outside#1#2{\let\next@=\relax
\ifnum\CIRlo@@>#1\DN@{#2}\else \ifnum#1<\CIRhi@@\else\DN@{#2}\fi\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Text}
??=[objectlib.text]
\DOCMODE(
\message{text;}
\DOCMODE)
Text in pictures is supported through the <object> construction
%
\begin{defs1}
|\txt| <width> <style> |{|<text>|}|\cr
\end{defs1}
\noindent\unskip
%
that builds an object containing <text> typeset to <width> using
<style>; in <text> |\\| can be used as an explicit line break; all
lines will be centered. <style> should either be a font command or
some other stuff to do for each line of the <text> and <width> should
be either |<|<dimen>|>| or <empty>.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The code just parses the <size> defaulting it to |<\maxdimen,0pt>|
which is recognised as `free form'.
\DOCMODE(
\xydef@\txt{\hbox\bgroup \xyFN@\txt@}
\xydef@\txt@{%
\addLT@\ifx\next \addGT@{\addLT@\DN@##1}{\A@=##1\txt@i}%
\else \DN@{\A@=\maxdimen \txt@i}\fi \next@}
\xydef@\txt@i#1#{%
\setboxz@h{#1\mathstrut}\dimen@=\ht\z@ \advance\dimen@\dp\z@
\baselineskip=1.1\dimen@ \lineskip=.2\dimen@ \lineskiplimit=\lineskip
\def\txtline@@##1{\txtline@{#1}{##1}}\object@\txt@ii}
\xylet@\txtline@@=\eat@
\xydef@\txtline@#1#2{\relax\setboxz@h{#1\ignorespaces #2\unskip}%
\ifdim\A@<\wdz@ \setboxz@h{\hsize=\A@
\leftskip=0pt plus4em \rightskip=\leftskip
\parfillskip=0pt \parindent=0pt %
\spaceskip=.3333em \xspaceskip=.5em %
\pretolerance=9999 \tolerance=9999 %
\hyphenpenalty=9999 \exhyphenpenalty=9999 %
\vbox{#1\noindent\ignorespaces #2\unskip}}%
\else\ifdim\A@<\maxdimen\setboxz@h to\A@{\hfil\boxz@\hfil}\fi\fi
\boxz@}
\xydef@\txt@ii#1{\vbox{%
\let\\=\cr
\tabskip=\z@skip \halign{\relax\hfil\txtline@@{##}\hfil\cr#1\crcr}}}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{\XY-pic option interface}
??=[option]
%
\NOTE: \LaTeX\ users should also consult the paragraph on ``xy.sty''
in~\S??[env.loading].
\XY-pic is provided with a growing number of options supporting
specialised drawing tasks as well as exotic output devices with
special graphic features. These should all be loaded using this
uniform interface in order to ensure that the \XY-pic environment is
properly set up while reading the option.
%
\begin{defs1}
%
|\xyoption| |{| <option> |}| \cr
|\xyrequire| |{| <option> |}|
%
\end{defs1}
\noindent\unskip
%
|\xyoption| will load the \XY-pic option file |xy|<option>|.tex|;
|\xyrequire| will do so only if it is not already loaded, if it is
then nothing happens.
\DOCMODE(
\message{options;}
\xylet@\xyoption@@=\relax
\xydef@\xyoption#1{\xyinputorelse@{xy#1}%
{\DN@{#1}\edef\next@{\codeof\next@}\xyerror@{No `\next@' option}{%
Your \string\xyoption\string{\next@\string} request could not be granted: the
required^^J%
file `xy\next@.tex' could not be located. Please make sure that it is^^J%
properly installed before continuing.}}%
\def\xyoption@@{#1}\edef\xyoption@@{\codeof\xyoption@@}\xywith@@
\ignorespaces}
\xydef@\xyrequire#1{\DN@{#1}%
\expandafter\let\expandafter\next@\csname xy\codeof\next@ loaded\endcsname
\ifx \next@\relax \DN@{\xyoption{#1}}\else \DN@{}\fi \next@}
\DOCMODE)
Sometimes some declarations of an option or header file or whatever
only makes sense after some particular other option is loaded. In
that case the code should be wrapped in the special command
%
\begin{defs1}
%
|\xywithoption| |{| <option> |}| |{| <code> |}| \cr
%
\end{defs1}
\noindent\unskip
%
which indicates that if the <option> is already loaded then <code>
should be executed now, otherwise it should be saved and if <option>
ever gets loaded then <code> should be executed afterwords.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NOTE: The <code> is saved with the catcodes at the time of the
|\xywithoption| command.
\DOCMODE(
\xylet@\xywith@@=\empty
\xydef@\xywithoption#1#2{\DN@{#1}%
\expandafter\let\expandafter\next@\csname xy\codeof\next@ loaded\endcsname
\ifx \next@\relax
\expandafter\def\expandafter\xywith@@\expandafter{\xywith@@
\DN@{#1}\edef\next@{\codeof\next@}%
\ifx\next@\xyoption@@ \DN@{#2}%
\else \let\next@=\relax \fi \next@}%
\else \DN@{#2}\fi \next@}
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Finally a description of the format of option files: they must look
like
\begin{quote}
|%%| <identification> \\
|%%| <copyright, \dots>
|\ifx\xyloaded\undefined \input xy \fi|
|\xyprovide{|<option>|}{|<name>|}{|<version>|}%| \\
\null\qquad\qquad |{|<author>|}{|<email>|}{|<address>|}|
??w![<body of the option>]
|\xyendinput|
\end{quote}
%
The 6 arguments to |\xyprovide| should contain the following:
%
\begin{description}
\item[<option>]
Option load name as used in the |\xyoption| command. This should be
safe and distinguishable for any operating system and is thus limited
to 6 characters chosen among the lowercase letters (|a|--|z|), digits
(|0|--|9|), and dash (|-|).
\item[<name>]
Descriptive name for the option.
\item[<version>]
Identification of the version of the option.
\item[<author>]
The name(s) of the author(s).
\item[<email>]
The electronic mail address(es) of the author(s) "or" the affiliation
if no email is available.
\item[<address>]
The postal address(es) of the author(s).
\end{description}
%
This information is used not only to print a nice banner but also to
(1)~silently skip loading if the same version was preloaded and
(2)~print an error message if a different version was preloaded.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The |\xyprovide| command checks that the option is not already loaded
and that the loaded version is the same as the preloaded one by
checking the existence and contents of the macro
|\xy|<option>|loaded|. Finally it calls |\xycatcodes| such that the
option internals are loaded in `\TeX\ programming mode'.
|\xyendinput| undoes this.
\DOCMODE(
\xydef@\xyprovide#1#2#3#4#5#6{%
\def\next{#1}\edef\next{\codeof\next}\edef\next@{#3}%
\message{XY-pic option: #2 v.\next@}%
\expandafter\let\expandafter\nextii@\csname xy\next loaded\endcsname
\ifx \next@\nextii@ \message{not reloaded}\endinput
\else
\ifx \nextii@\relax\else \xyerror@{Option `\next' version mismatch}{%
You previously loaded, or the format has preloaded, a different version^^J%
of this option. Just hit return to try to load this version instead (and^^J%
be prepared for a lot of warnings about redefinitions).}%
\fi
\expandafter\let\csname xy\next loaded\endcsname=\next@
\expandafter\let\expandafter\xyenddocmode@\csname DOCMODE\endcsname
\expandafter\let\csname DOCMODE\endcsname\xyprovidedocmode@
\xycatcodes
\fi \ignorespaces}
\xydef@\xyendinput{\expandafter\let\csname DOCMODE\endcsname=\xyenddocmode@
\message{loaded}\xyuncatcodes\endinput}
\DOCMODE)
It is futher complicated by the |DOCMODE| format (see below).
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph*{DOCMODE format:}
Some trickery is involved because options may use the |DOCMODE|
format without any restrictions. So we make sure that the dummy one
defined in the |xy.tex| file header is active now since we are
executing code.
\DOCMODE(
\expandafter\xylet@\expandafter\xyprovidedocmode@\csname DOCMODE\endcsname
\xylet@\xyenddocmode@=\relax
\DOCMODE)
Options should be written in the special |DOCMODE| format in order to
be included in the distribution proper. The `dummy' option described
in~\S??g[:dummy] shows a minimal such option.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Algorithms}
??=[algo]
This section presents the more complicated algorithms used in
\XY-pic.
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Directions}
??=[algo.direction]
\DOCMODE(
\message{algorithms: directions,}
\DOCMODE)
The "direction state" is described by the following parameters:
%
\begin{defs}
"Direction" & `angle' of the direction on $]-4K\dots4K]$ unit square \cr
"dX","dY" & the vector $c-p$ \cr
"sdX","sdY" & sign of "dX" and "dY" \cr
|\K@dXdY|,|\K@dYdX| & quotients $K\frac{"dX"}{"dY"}$ and
$K\frac{"dY"}{"dX"}$ (as dimensions in sp) \cr
"DirectionChar","SemiDirectionChar" & |\chardefs| for directional
and semidirectional fonts \cr
"cosDirection","sinDirection" & factors in the range $]-1\dots1]$
corresponding to cos and sin of Direction \cr
\end{defs}
%
where the ``$]-4K\dots4K]$ unit square'' has the following angles:
$$
\xy *[]=<3pc>{}="c"*\frm{-},
"c"; (-1,-1)**{},p+/4pc/ *+{0} **\dir{-}?>*\dir{>},
"c"; ( 0,-1)**{},p+/4pc/ *+{K} **\dir{-}?>*\dir{>},
"c"; ( 1,-1)**{},p+/4pc/ *+{2K} **\dir{-}?>*\dir{>},
"c"; ( 1, 0)**{},p+/4pc/ *+{3K} **\dir{-}?>*\dir{>},
"c"; ( 1, 1)**{},p+/4pc/ *+{4K} **\dir{-}?>*\dir{>},
"c"; ( 0, 1)**{},p+/4pc/ *+{{-}3K} **\dir{-}?>*\dir{>},
"c"; (-1, 1)**{},p+/4pc/ *+{{-}2K} **\dir{-}?>*\dir{>},
"c"; (-1, 0)**{},p+/4pc/ *+{{-}K} **\dir{-}?>*\dir{>},
\endxy
$$
where the intermediate $K$ angle in each interval correspond to
equidistant points on the unit square. Thus only for
$n\in\{-3,2,1,0,1,2,3,4\}$ the angle of direction $n*K$ is exactly
$n*45^\circ - 135^\circ$ ($0^\circ$ being the direction straight
right).
As usual |\DirectionfromtheDirection@| expands to code setting the
current direction.
\DOCMODE(
\xydef@\DirectionfromtheDirection@{\noexpand\Direction=\the\Direction
\noexpand\dX=\the\dX \noexpand\dY=\the\dY
\def\noexpand\sdX{\sdX}\def\noexpand\sdY{\sdY}%
\noexpand\K@dXdY=\the\K@dXdY \noexpand\K@dYdX=\the\K@dYdX
\chardef\noexpand\DirectionChar=\the\DirectionChar
\chardef\noexpand\SemiDirectionChar=\the\SemiDirectionChar
\def\noexpand\cosDirection{\cosDirection}%
\def\noexpand\sinDirection{\sinDirection}%
\noexpand\resetupDirection@}
\DOCMODE)
The actual direction computation is done using
|\setupDirection@|.
\paragraph*{Procedure:}
%
Is really not so complicated. [??_[Dir1]]~"dX" and "dY" are computed
from $c-p$ and we skip if the current setting is based on these (this
is stored in the internal |\Directiontest@@| method);
[??_[Diri1]]~if the direction is one of the principal ones then
proceed with an optimised special case for those; otherwise proceed
with the generic code.
\DOCMODE(
\xydef@\Directiontest@@#1#2{#2}
\xydef@\setupDirection@{%
\dX=\Xc\advance\dX-\Xp \dY=\Yc\advance\dY-\Yp %?*[Dir1]
\Directiontest@@\relax\setupDirection@i}
\xydef@\setupDirection@i{\DN@{\setupDirection@ii}% %?*[Diri1]
\ifdim\dX=\dY
\ifdim\dY=\z@ \DN@{}%
\else\ifdim\dX<\z@ \DN@{\dlDirection@{-1.4142\dX}}%
\else \DN@{\urDirection@{1.4142\dX}}\fi\fi
\else\ifdim\dX<\dY
\ifdim\dX=\z@ \DN@{\uDirection@\dY}%
\else\ifdim\dY=\z@ \DN@{\lDirection@{-\dX}}%
\else\ifdim-\dX=\dY \DN@{\ulDirection@{-1.4142\dX}}\fi\fi\fi
\else
\ifdim\dX=\z@ \DN@{\dDirection@{-\dY}}%
\else\ifdim\dY=\z@ \DN@{\rDirection@\dX}%
\else\ifdim\dX=-\dY \DN@{\drDirection@{1.4142\dX}}\fi\fi\fi
\fi\fi \next@}
\DOCMODE)
The procedures for the special <diag>onal cases are summarised in
this table:
$$
\let\|=\otherbar
\begin{array}{\|c\|r\|rl\|c\|rl\|}
\hline
\mbox{<diag>onal} & "Direction" & \cos("Direction"),& \sin("Direction")
& "sign"("dX","dY") & "Char" & "Semi" \\
\hline
|dl| & 0 & {-\sqrt{\frac12}},& {-\sqrt{\frac12}} & -,- & 127 & 127 \\
|d| & K & 0,& -1 & +,- & 15 & 31 \\
|dr| & 2K & {\sqrt{\frac12}},& {-\sqrt{\frac12}} & +,- & 31 & 63 \\
|r| & 3K & 1,& 0 & +,+ & 47 & 95 \\
|ur| & 4K & {\sqrt{\frac12}},& {\sqrt{\frac12}} & +,+ & 63 & 127 \\
|u| &-3K & 0,& 1 & +,+ & 79 & 31 \\
|ul| &-2K & {-\sqrt{\frac12}},& {\sqrt{\frac12}} & -,+ & 95 & 63 \\
|l| & -K & -1,& 0 & -,+ & 111 & 95 \\
\hline
\end{array}
$$
In each case the argument is used as the unit circle, \ie, non-zero
of "dX" and "dY", and $|<|K\frac{"dX"}{"dY"}|,|K\frac{"dY"}{"dX"}|>|
:= "KK"*|<|"dX"|,|"dY"|>|$\dots
\DOCMODE(
\xydef@\dlDirection@{\Direction=\z@
\def\cosDirection{-.7071}\def\sinDirection{-.7071}\def\sdX{-}\def\sdY{-}%
\chardef\DirectionChar=127\relax\chardef\SemiDirectionChar=127\relax
\K@dXdY=1\K \K@dYdX=1\K \fixedDirection@}
\xydef@\dDirection@{\Direction=\K
\def\cosDirection{0}\def\sinDirection{-1}\def\sdX{+}\def\sdY{-}%
\chardef\DirectionChar=15\relax\chardef\SemiDirectionChar=31\relax
\K@dXdY=\z@ \K@dYdX=\KK@\K \fixedDirection@}
\xydef@\drDirection@{\dimen@ii=2\K \Direction=\dimen@ii
\def\cosDirection{+.7071}\def\sinDirection{-.7071}\def\sdX{+}\def\sdY{-}%
\chardef\DirectionChar=31\relax\chardef\SemiDirectionChar=63\relax
\K@dXdY=-1\K \K@dYdX=-1\K \fixedDirection@}
\xydef@\rDirection@{\dimen@ii=3\K \Direction=\dimen@ii
\def\cosDirection{+1}\def\sinDirection{0}\def\sdX{+}\def\sdY{+}%
\chardef\DirectionChar=47\relax\chardef\SemiDirectionChar=95\relax
\K@dXdY=\KK@\K \K@dYdX=\z@ \fixedDirection@}
\xydef@\urDirection@{\dimen@ii=4\K \Direction=\dimen@ii
\def\cosDirection{+.7071}\def\sinDirection{+.7071}\def\sdX{+}\def\sdY{+}%
\chardef\DirectionChar=63\relax\chardef\SemiDirectionChar=127\relax
\K@dXdY=1\K \K@dYdX=1\K \fixedDirection@}
\xydef@\uDirection@{\dimen@ii=-3\K \Direction=\dimen@ii
\def\cosDirection{0}\def\sinDirection{+1}\def\sdX{+}\def\sdY{+}%
\chardef\DirectionChar=79\relax\chardef\SemiDirectionChar=31\relax
\K@dXdY=\z@ \K@dYdX=\KK@\K \fixedDirection@}
\xydef@\ulDirection@{\dimen@ii=-2\K \Direction=\dimen@ii
\def\cosDirection{-.7071}\def\sinDirection{+.7071}\def\sdX{-}\def\sdY{+}%
\chardef\DirectionChar=95\relax\chardef\SemiDirectionChar=63\relax
\K@dXdY=-1\K \K@dYdX=-1\K \fixedDirection@}
\xydef@\lDirection@{\Direction=-\K
\def\cosDirection{-1}\def\sinDirection{0}\def\sdX{-}\def\sdY{+}%
\chardef\DirectionChar=111\relax\chardef\SemiDirectionChar=95\relax
\K@dXdY=\KK@\K \K@dYdX=\z@ \fixedDirection@}
\xydef@\fixedDirection@#1{\dimen@ii=#1\relax
\dX=\cosDirection\dimen@ii \dY=\sinDirection\dimen@ii
\resetupDirection@}
\DOCMODE)
Here is the procedure for the generic code.
%
\begin{itemize}
\item[{??_[Dirii1]}]
Make sign variables and slopes: $"sdX" := "sign"("dX")$, $"sdY" :=
"sign"("dY")$, $K\frac{"dX"}{"dY"} :=
"sdX"*"sdY"*\floor{\abs{"KK"*"dX"} / \abs{"dY"/"KK"}}$, and
$K\frac{"dY"}{"dX"} := "sdX"*"sdY"*\floor{\abs{"KK"*"dY"} /
\abs{"dX"/"KK"}}$, where the somewhat exotic computation method is
used to ensure that the `native' floor function provided by \TeX\
|\divide| can be used (it only acts predictably for positive
numbers), that overflow is avoided even for large $"dX","dY"$, and
that it is reasonable to use the convention of |\quotient@| that
division by zero is like multiplying with one\dots Also takes care
not to multiply to big dimensions with each other.
\item[{??_[Dirii2]}]
If ${-K} \le K\frac{"dX"}{"dY"} \le K$ then the direction is mostly
up or down: if $"dY"\lt0$ [down, ??_[Dirii2a]]: $"Direction" := -
K\frac{"dX"}{"dY"} + 1K$; else [up, ??_[Dirii2b]]: $"Direction" := -
K\frac{"dX"}{"dY"} - 3K$.
\item[{??_[Dirii3]}]
If ${-K} \lt K\frac{"dY"}{"dX"} \lt K$ then direction is mostly left
or right: if $"dX"\lt0$ [left, ??_[Dirii3a]]: $"Direction" :=
K\frac{"dY"}{"dX"} - K$; else [right, ??_[Dirii3b]]: $"Direction" :=
K\frac{"dY"}{"dX"} + 3K$.
\item[{??_[Dirii4]}]
Compute character codes for direction and semidirection fonts.
[??_[Dirii4a]]: $"DirectionChar" := (8K+"Direction"+K/32)
\hbox{~div~} (K/16) - 1$; while $"DirectionChar" \gt 127:
"DirectionChar" -:= 128$. [??_[Dirii4b]]: $"SemiDirectionChar" :=
(8K+"Direction"+K/64) \hbox{~div~} (K/32) - 1$; while
$"SemiDirectionChar" \gt 127: "SemiDirectionChar" -:= 128$. In both
cases the $8K$ are added to ensure that \TeX\ will round down.
\HACK: The |16|, |\KK@|, and |64| in these lines are really $K/64$,
$K/32$, and $K/16$\dots
\item[{??_[Dirii5]}]
Build "cosDirection" and "sinDirection" from appropriate characters
in the |\xydashfont|. [??_[Dirii5]]: $"cosDirection" :=
"wd"(|\xydashfont| "SemiDirectionChar")$. [??_[Dirii5b]] $C :=
"SemiDirectionChar"-64$, if $C\lt0$: $C := C+128$, $"sinDirection" :=
"wd"(|\xydashfont| C)$.
\item[{??_[Dirii6]}]
Register this "dX","dY" for next time.
\end{itemize}
\DOCMODE(
\xydef@\setupDirection@ii{%
\ifdim\dX<\z@ \def\sdX{-}\else \def\sdX{+}\fi %?*[Dirii1]
\ifdim\dY<\z@ \def\sdY{-}\else \def\sdY{+}\fi
\K@dXdY=\sdX\dX \ifdim\K@dXdY<500pt \multiply\K@dXdY\KK@ \fi \dimen@=\sdY\dY
\advance\dimen@.5\KK@ \divide\dimen@\KK@
\ifdim\dimen@=\z@\else %\count@=\dimen@ \divide\count@\tw@
\advance\K@dXdY by.5\dimen@\relax \divide\K@dXdY\dimen@
\fi \K@dXdY=\sdX\sdY\K@dXdY
\K@dYdX=\sdY\dY \ifdim\K@dYdX<500pt \multiply\K@dYdX\KK@ \fi \dimen@=\sdX\dX
\advance\dimen@.5\KK@ \divide\dimen@\KK@
\ifdim\dimen@=\z@\else %\count@=\dimen@ \divide\count@\tw@
\advance\K@dYdX by.5\dimen@\relax \divide\K@dYdX\dimen@
\fi \K@dYdX=\sdX\sdY\K@dYdX
\Direction=\maxdimen
\ifnum\K@dXdY<-\K \else \ifnum\K<\K@dXdY \else %?*[Dirii2]
\ifdim \dY<\z@ %?*[Dirii2a]
\Direction=\K \advance\Direction-\K@dXdY
\else %?*[Dirii2b]
\Direction=\K \multiply\Direction-\thr@@ \advance\Direction-\K@dXdY
\fi\fi\fi
\ifnum-\K<\K@dYdX \ifnum\K@dYdX<\K %?*[Dirii3]
\ifdim \dX<\z@ %?*[Dirii3a]
\Direction=-\K \advance\Direction\K@dYdX
\else %?*[Dirii3b]
\Direction=\K \multiply\Direction\thr@@ \advance\Direction\K@dYdX
\fi\fi\fi
\ifnum\Direction=\maxdimen
\Direction=\K@dYdX \advance\Direction-\K@dXdY \divide\Direction\tw@
\ifnum\K@dXdY<\z@ \advance\Direction\K \advance\Direction\K
\else \advance\Direction-\K \advance\Direction-\K \fi
\fi
\count@@=\K \multiply\count@@ by8 \advance\count@@\Direction %?*[Dirii4]
\count@=\count@@ \advance\count@\KK@ \divide\count@64 \advance\count@\m@ne %?*[Dirii4a]
\loop@\ifnum127<\count@ \advance\count@-128 \repeat@
\chardef\DirectionChar\count@
\advance\count@@16 \divide\count@@\KK@ \advance\count@@\m@ne %?*[Dirii4b]
\loop@\ifnum127<\count@@ \advance\count@@-128 \repeat@
\chardef\SemiDirectionChar\count@@
\setbox8=\hbox{\xydashfont\SemiDirectionChar\/}% %?*[Dirii5]
\quotient@@\cosDirection{\sdX\wd8}\xydashl@
\setbox8=\hbox{\xydashfont\count@=\SemiDirectionChar\advance\count@-64 %?*[Dirii5b]
\ifnum\count@<\z@ \advance\count@128 \fi \char\count@\/}%
\quotient@@\sinDirection{\sdY\wd8}\xydashl@
\resetupDirection@ %?*[Dirii6]
}
\DOCMODE)
Finally some special cases used by the <direction>s and directional
library objects. All manipulate the Direction dependent parameters
and then call |\resetupDirection@|: |\reverseDirection| reverses it;
|\above|- and |\belowDirection@| are for |^| and |_|, and
$|\vDirection@(|x|,|y|){|L|}|$ is for $|:(|x|,|y|)|$, \ie, computes
a new direction as the vector
$$
|<| X - x*\cos\alpha*L - y*({-}\sin\alpha)*L |,|
Y - x*\sin\alpha*L - y*\cos\alpha*L |>|
$$
where $\alpha$ is the previous direction angle.
\DOCMODE(
\xydef@\reverseDirection@{%
\dX=-\dX \dY=-\dY
\ifdim\dX<\z@ \def\sdX{-}\else \def\sdX{+}\fi
\ifdim\dY<\z@ \def\sdY{-}\else \def\sdY{+}\fi
\dimen@=4\K \ifnum\Direction<\z@ \advance\Direction\dimen@
\else \advance\Direction-\dimen@ \fi
\count@=\DirectionChar \ifnum\count@<64 \advance\count@64 %
\else \advance\count@-64 \fi \chardef\DirectionChar=\count@
\edef\cosDirection{\if-\cosDirection\else-\cosDirection\fi}%
\edef\sinDirection{\if-\sinDirection\else-\sinDirection\fi}%
\resetupDirection@}
\xydef@\aboveDirection@#1{%
\dimen@=\dX \dX=-\dY \dY=\dimen@
\dimen@=\K@dXdY \K@dXdY=-\K@dYdX \K@dYdX=-\dimen@
\ifdim\dX<\z@ \def\sdX{-}\else \def\sdX{+}\fi
\ifdim\dY<\z@ \def\sdY{-}\else \def\sdY{+}\fi
\dimen@=2\K \ifdim 1\Direction<\dimen@\else \dimen@=-6\K \fi
\advance\Direction\dimen@
\count@=\DirectionChar \ifnum\count@<96 \advance\count@32 %
\else \advance\count@-96 \fi \chardef\DirectionChar=\count@
\count@=\SemiDirectionChar \ifnum\count@<64 \advance\count@64 %
\else \advance\count@-64 \fi \chardef\SemiDirectionChar=\count@
\let\tmp@=\cosDirection
\edef\cosDirection{\if-\sinDirection\else-\sinDirection\fi}%
\let\sinDirection=\tmp@
\dimen@=#1\relax \dX=\cosDirection\dimen@ \dY=\sinDirection\dimen@
\resetupDirection@}
\xydef@\belowDirection@#1{%
\dimen@=\dX \dX=\dY \dY=-\dimen@
\dimen@=\K@dXdY \K@dXdY=-\K@dYdX \K@dYdX=-\dimen@
\ifdim\dX<\z@ \def\sdX{-}\else \def\sdX{+}\fi
\ifdim\dY<\z@ \def\sdY{-}\else \def\sdY{+}\fi
\dimen@=-2\K\ifdim 1\Direction<\dimen@\dimen@=6\K\fi \advance\Direction\dimen@
\count@=\DirectionChar \ifnum\count@<32 \advance\count@96 %
\else \advance\count@-32 \fi \chardef\DirectionChar=\count@
\count@=\SemiDirectionChar \ifnum\count@<64 \advance\count@64 %
\else \advance\count@-64 \fi \chardef\SemiDirectionChar=\count@
\let\tmp@=\sinDirection
\edef\sinDirection{\if-\cosDirection\else-\cosDirection\fi}%
\let\cosDirection=\tmp@
\dimen@=#1\relax \dX=\cosDirection\dimen@ \dY=\sinDirection\dimen@
\resetupDirection@}
\xydef@\vDirection@(#1,#2)#3{\dimen@ii=#3\relax
\dimen@=#1\dimen@ii \dimen@ii=#2\dimen@ii
\dX=\cosDirection\dimen@ \advance\dX-\sinDirection\dimen@ii
\dY=\sinDirection\dimen@ \advance\dY \cosDirection\dimen@ii
\Xp=\Xc \advance\Xp-\dX \Yp=\Yc \advance\Yp-\dY
\setupDirection@\ignorespaces}
\DOCMODE)
The above all make use of the following; use them also when the
direction state is known to be correct: |\resetDirection@| should be
called when $p$ and/or $c$ are moved along the line $\vec{pc}$,
|\resetupDirerection| when the entire direction state is changed in a
consistent manner.
\DOCMODE(
\xydef@\resetDirection@{%
\dX=\Xc\advance\dX-\Xp \dY=\Yc\advance\dY-\Yp \let\next@=\resetupDirection@
\ifdim\sdX\dX<\z@ \let\next@=\setupDirection@i \fi
\ifdim\sdY\dY<\z@ \let\next@=\setupDirection@i \fi
\next@}
\xydef@\resetupDirection@{%
\edef\Directiontest@@##1##2{\noexpand\DN@{##2}%
\noexpand\ifdim\noexpand\dX=\the\dX\relax
\noexpand\ifdim\noexpand\dY=\the\dY\relax \noexpand\DN@{##1}%
\noexpand\fi\noexpand\fi \noexpand\next@}}
\xydef@\unsetupDirection@{\def\Directiontest@@##1##2{##2}}
\DOCMODE)
Finally the initial direction: up!
\DOCMODE(
\uDirection@\xydashl@
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Edges}
??=[algo.edge]
An "Edge" is a token list describing the edge of an object. It must
have the form |{|<expandable token> <unexpandable tokens>|}|.
To find the edge of an object then first make it the current object
and then do
$$
|\the\Edgec|<code>
$$
where <code> determines what should be done:
%
\begin{itemize}
\item[0]
$c$ is changed to be equal to the point on the edge intersecting with
the line segment from $p$ (this is the v2.6 behaviour).
\NOTE: This should not change any of $A$, $B$, or any component of
the state except $X_c$ and $Y_c$!
\item[1]
Test whether the center of $p$, \ie, $|<|X_p|,|Y_p|>|$, is `inside'
the $c$ object (or on the edge). Sets the test |\ifInside@|
accordingly.
\item[2]
Set |\dimen@| to the distance from the center to the edge towards~$p$
(as set with code~0).
\NOTE: This is only positive in the direction towards $p$
(thus negative-sized circles and rectangles make it negative).
\item[3]
$c$ is changed to be equal to the point on the edge furthest in the
direction towards $p$.
\NOTE: This should not change any of $A$, $B$, or any component of
the state except $X_c$ and $Y_c$!
\item[4]
Replace $c$ with rectangle with corners where the line from $p$
intersects with the edge of $c$ (thus this is the inner rectangle
with corners as the current direction dictates).
\item[5]
Replace $c$ with smallest rectangle that encloses the current object
completely.
\end{itemize}
%
(if this reminds the reader of a `dictionary' as used by
object-oriented programming languages then they probably share this
authors regret that \TeX\ is not object oriented :-)
\DOCMODE(
\message{edges,}
\xynew@{if}\ifInside@
\DOCMODE)
\paragraph*{Points:}
The simplest shape is none at all -- a point.
\DOCMODE(
\xydef@\zeroEdge#1{%
\ifcase#1\relax \or \Inside@false \or \dimen@=\z@
\or \or \else \Edgec={\rectangleEdge}\fi}
\DOCMODE)
\paragraph*{Circles:}
Next we define round things: Code~0 moves $|<|X_c|,|Y_c|>|$ to the
point $|<|X_c - R_c*\cos\alpha|,| Y_c - R_c*\sin\alpha|>|$ where
$\alpha$ is the current direction angle, code~1 tests whether the
$p$ center is located between those two points., code~2 just returns
the radius, code~3 is as code~0 and code~4 is the only nontrivial
one, replacing with the inner symmetric rectangle with corner at the
point of code~0.
\DOCMODE(
\xydef@\circleEdge#1{\ifcase#1\expandafter\circleEdge@
\or \expandafter\circleUnder@ \or \dimen@=\Rc
\or \expandafter\circleEdge@ \or \expandafter\circleInner@
\else \expandafter\circleOuter@ \fi}
\xydef@\circleEdge@{%
\dimen@=-\cosDirection\Rc \advance\Xc\dimen@
\dimen@=-\sinDirection\Rc \advance\Yc\dimen@}
%\xydef@\circleUnder@{\Inside@false
% \ifdim\Xp=\Xc \ifdim\Yp=\Yc \Inside@true \fi\fi
% \ifInside@ \else{\setupDirection@
% \dimen@=\cosDirection\Rc \dimen@=\sdX\dimen@
% \dimen@ii=\sinDirection\Rc \dimen@ii=\sdY\dimen@ii
% \ifdim\dimen@>\dimen@ii
% \ifdim\sdX\dX<\dimen@\aftergroup\Inside@true\fi
% \else
% \ifdim\sdY\dY<\dimen@ii\aftergroup\Inside@true\fi
% \fi}\fi }
\xydef@\circleUnder@{\Inside@false
\ifdim\Xp=\Xc \relax \ifdim\Yp=\Yc \Inside@true \fi \fi
\ifInside@ \else \expandafter \circleCentre@ \fi }
\xydef@\circleCentre@{{%
\ifdim\Lc=\Rc \relax\else
\dimen@=\Rc\advance\dimen@-\Lc \divide\dimen@\tw@
\advance\Xc\dimen@ \advance\Rc-\dimen@ \fi
\dX=\Xc \advance\dX-\Xp \dX=\ifdim\dX<\z@-\fi\dX
\ifdim\Uc=\Dc\relax \else
\dimen@=\Uc\advance\dimen@-\Dc \divide\dimen@\tw@
\advance\Yc\dimen@ \advance\Uc-\dimen@ \fi
\dY=\Yc \advance\dY-\Yp \dY=\ifdim\dY<\z@-\fi\dY
\DN@{}\ifdim\dX>\Rc \relax \else \ifdim\dY>\Uc \relax
\else \ifdim\Uc=\Rc \DN@{\circleUnder@@}%
\else \DN@{\ellipseUnder@@}\fi
\fi\fi \next@ }}
\xydef@\circleUnder@@{%
\loop\ifdim\Rc>100\p@ \circlescale@ \repeat
\edef\tmp@{\expandafter\removePT@\the\Rc}\dimen@=\tmp@\Rc
\edef\tmp@{\expandafter\removePT@\the\dX}\advance\dimen@-\tmp@\dX
\edef\tmp@{\expandafter\removePT@\the\dY}\advance\dimen@-\tmp@\dY
\ifdim\dimen@>\z@ \aftergroup\Inside@true \fi }
\xydef@\circlescale@{\divide\Rc\KK@ \divide\dX\KK@ \divide\dY\KK@ }
\xydef@\ellipseUnder@@{%
\ifdim\Rc>64\p@ \circlescale@ \divide\Uc\KK@
\else \ifdim\Uc>64\p@ \circlescale@ \divide\Uc\KK@ \fi\fi
\edef\tmp@{\expandafter\removePT@\the\Rc}\dY=\tmp@\dY
\edef\tmp@{\expandafter\removePT@\the\Uc}\dX=\tmp@\dX
\Rc=\tmp@\Rc \circleUnder@@ }
\xydef@\circleInner@{%
\Lc=\sdX\cosDirection\Rc \Dc=\sdY\sinDirection\Rc
\Rc=\Lc \Uc=\Dc \Edgec={\rectangleEdge}}
\xydef@\circleOuter@{%
\Lc=\Rc \Dc=\Rc \Uc=\Dc \Edgec={\rectangleEdge}}
\DOCMODE)
\BUG: It is assumed that the circle has reference point in its
center; the radius is taken directly from $R_c$.
\paragraph*{Rectangles:}\leavevmode
Rectangles intersection is slightly more complicated and handled
separately for the horizontal and vertical case.
\DOCMODE(
\xydef@\rectangleEdge#1{\ifcase#1\expandafter\rectangleEdge@
\or \expandafter\rectangleUnder@ \or \expandafter\rectangleWidth@
\or \expandafter\rectangleProp@
\else \relax \fi}
\DOCMODE)
\DOCMODE(
% \rectangleEdge@
% Sets <X,Y> to the intersection of a line from <X-dX,Y-dY> to <X,Y>
% and the rectangle from <X-L,Y-D> to <X+R,Y+U>:
%
% %1a dY<0, dX<0: X := X + min{R, U*|dX/dY|},
% Y := Y + min{U, R*|dY/dX|};
% b dY<0, dX=0: Y := Y + U;
% c dY<0, dX>0: X := X - min{L, U*|dX/dY|},
% Y := Y + min{U, L*|dY/dX|};
%
% %2a dY=0, dX<0: X := X + R;
% b dY=0, dX=0: ;
% c dY=0, dX>0: X := X - L;
%
% %3a dY>0, dX<0: X := X + min{R, D*|dX/dY|},
% Y := Y - min{D, R*|dY/dX|};
% b dY>0, dX=0: Y := Y - D;
% c dY>0, dX>0: X := X - min{L, D*|dX/dY|},
% Y := Y - min{D, L*|dY/dX|};
%
% %4 \resetupDirection@ to register that even though dX,dY changed all
% Direction parameters are is still valid!
%
% NOTE: d=0 really means |d| < .05pt.
%
\xydef@\rectangleEdge@{%
\ifdim\dY<-.05\p@ \rectangleEdge@i %1
\else\ifdim\dY<.05\p@ \rectangleEdge@ii %2
\else \rectangleEdge@iii\fi\fi
\resetupDirection@}
\xydef@\rectangleEdge@i{%
\ifdim\dX<-.05\p@ \settomin@\Xc+\Rc\Uc\dX\dY \settomin@\Yc+\Uc\Rc\dY\dX%1a
\else\ifdim\dX<.05\p@ \advance\Yc\Uc %1b
\else \settomin@\Xc-\Lc\Uc\dX\dY \settomin@\Yc+\Uc\Lc\dY\dX %1c
\fi\fi}
\xydef@\rectangleEdge@ii{%
\ifdim\dX<-.05\p@ \advance\Xc\Rc %2a
\else\ifdim\dX<.05\p@ %2b
\else \advance\Xc-\Lc %2c
\fi\fi}
\xydef@\rectangleEdge@iii{%
\ifdim\dX<-.05\p@ \settomin@\Xc+\Rc\Dc\dX\dY \settomin@\Yc-\Dc\Rc\dY\dX%3a
\else\ifdim\dX<.05\p@ \advance\Yc-\Dc %3b
\else \settomin@\Xc-\Lc\Dc\dX\dY \settomin@\Yc-\Dc\Lc\dY\dX %3c
\fi\fi}
\xydef@\settomin@#1#2#3#4#5#6{%
% Perform d := #2 min{#3, #4*|#5/#6|}; #1 := #1+d ...
\edef\nextii@{\A@=\the\A@ \B@=\the\B@}\quotient@\next@{#5}{#6}\nextii@
\dimen@=\sdX\sdY\next@#4\relax
\ifdim#3<\dimen@ \dimen@=#3\fi \advance#1#2\dimen@}
\DOCMODE)
Checking that $p$ is under is simpler:
\DOCMODE(
\xydef@\rectangleUnder@{\Inside@false
\ifdim\Xp=\Xc \ifdim\Yp=\Yc \Inside@true \fi\fi
\ifInside@ \else
\dimen@=\Xp \advance\dimen@-\Xc
\ifdim \dimen@>-\Lc \relax \ifdim\dimen@<\Rc
\dimen@=\Yp \advance\dimen@-\Yc
\ifdim \dimen@>-\Dc \relax \ifdim\dimen@<\Uc
\Inside@true
\fi\fi\fi\fi\fi }
\DOCMODE)
Calculating the width is like computing the edge point just simpler:
\DOCMODE(
\xydef@\rectangleWidth@{\let\next@=\rectangleWidth@i
\ifdim\dX<-.05\p@ \A@=\Rc
\else\ifdim\dX<.05\p@ \A@=\z@ \DN@{\dimen@=\B@}%
\else \A@=\Lc \fi\fi
\ifdim\dY<-.05\p@ \B@=\Uc
\else\ifdim\dY<.05\p@ \DN@{\dimen@=\A@}%
\else \B@=\Dc \fi\fi
\next@}
\xydef@\rectangleWidth@i{%
\begingroup
\dimen@=\sdX\cosDirection\B@
\quotient@\next\dimen@{\sdY\sinDirection\p@}\dimen@=\next\dimen@
\edef\next{\endgroup \dimen@=\the\dimen@}%
\ifdim\dimen@<\B@ \B@=\the\dimen@ \fi
\begingroup
\dimen@=\sdY\sinDirection\A@
\quotient@\next\dimen@{\sdX\cosDirection\p@}\dimen@=\next\dimen@
\edef\next{\endgroup \dimen@=\the\dimen@}%
\ifdim\dimen@<\A@ \A@=\the\dimen@ \fi
\dimen@=\sdX\cosDirection\A@ \advance\dimen@\sdY\sinDirection\B@}
\DOCMODE)
Setting $c$ to the `proportional edge point' is straight out of
v2.6's |\setlabel@@| macro\dots
\DOCMODE(
% First rotate to opposite direction.
% Then compute Leftf,Upf [\next@,\nextii@]:
% 0,(D-2K)/2K for 2K < D <= 4K [right]
% (2K-D)/2K,0 for 0 < D <= 2K [down]
% 1,-D/2K for -2K < D <= 0 [left]
% (D+4K)/2K,1 for -4K < D <= -2K [up]
% Finally set <X,Y> to
% < X - L + Leftf*(R+L) , Y + U - Upf*(D+U) >
\xydef@\rectangleProp@{%
%
\enter@{\A@=\the\A@ \B@=\the\B@ \DirectionfromtheDirection@}%
%
% \count@@@=\Direction
% \dimen@=4\K \ifnum\count@>\z@ \advance\count@@@-\dimen@
% \else \advance\count@@@\dimen@ \fi
%
\reverseDirection@
%
\dimen@=1\Direction \count@=\K \multiply\count@\tw@
\ifnum \Direction>\count@
\DN@{0}%
\advance\dimen@-2\K \quotient@\nextii@{\dimen@}{2\K}%
\else\ifnum \Direction>\z@
\dimen@=-\dimen@ \advance\dimen@2\K \quotient@\next@{\dimen@}{2\K}%
\DNii@{0}%
\else\ifnum \Direction>-\count@
\DN@{1}%
\quotient@\nextii@{-\dimen@}{2\K}%
\else
\advance\dimen@4\K \quotient@\next@{\dimen@}{2\K}%
\DNii@{1}%
\fi\fi\fi
%
% \advance\Xc-\Lc \dimen@=\Lc \advance\dimen@\Rc \advance\Xc\next@\dimen@
% \advance\Yc+\Uc \dimen@=\Dc \advance\dimen@\Uc \advance\Yc-\nextii@\dimen@
\advance\Xc-\Lc \dimen@=\Lc \advance\dimen@\Rc
\ifdim\dimen@=\z@ \advance\Xc 2\Lc \else \advance\Xc\next@\dimen@ \fi
\advance\Yc+\Uc \dimen@=\Dc \advance\dimen@\Uc
\ifdim\dimen@=\z@ \advance\Yc-2\Uc \advance\Yc\Upness@\Uc
\else \advance\Yc-\nextii@\dimen@ \fi
%
\leave@}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Connections}
??=[algo.connection]
\TODO: Complete conversion to |DOCMODE| form.
\DOCMODE(
\message{connections;}
% Connections describe how a particular OBJECT may be used to connect p to c.
% The following parameters are used:
%
% Invisible@@, Hidden@@, Drop@@: from OBJECT.
%
% lastobjectbox@: box to fill with; assumed to be `trimmed' to have
% only the size needed for the filler; size is w*(h+d) (this is
% handled, e.g., by the POS ** interpretion \connect@).
%
% and defines the following parameters in addition to actually typesetting
% the connection:
\DOCMODE)
The following methods are defined by any connection; they should be
used in the indicated sequence:??w[connection methods]
\begin{description}
\item[|\Creset@@|:]
(Re)set the connection parameters to allow use of the following to
move to a point on the connection (this is what the interpretation of
<pos> |?| does first).
\item[|\Cshavep@@| or |\Cshavec@@|:]
Move $p$ or $c$ to the start or finish of the connection. These may
be called several times or not at all.
\item[|\Calong@@{|<factor>|}|:]
Move $c$ to point the <factor> along the connection and set the
direction parameters as a tangent to it in this point.
\item[|\Cslidep@@{|<dimen>|}| or |\Cslidec@@{|<dimen>|}|:]
Move $p$ or $c$ the <dimen>sion further in the current direction.
Can be used both before and after the |\Calong@@| method.
\end{description}
\DOCMODE(
\xydef@\Creset@@{}
\xydef@\Cshavep@@{\noCshavep@@}
\xydef@\Cshavec@@{\noCshavec@@}
\xydef@\Cslidep@@{\noCslidep@@}
\xydef@\Cslidec@@{\noCslidec@@}
\xydef@\Calong@@{\noCalong@@}
% NOTE: Basic XY-pictures only have straight connections and thus the C* macros
% given here are rather simple...in particular you should not make use of the
% Direction parameters until after calling Calong@@{F}!
% \no@@
% Dummy connection for use with OBJECTS where it just does not make
% sense to build connections...or just setup a dummy straight
% connection :-)
\xydef@\no@@{\setupDirection@
\edef\Creset@@{\cfromthec@ \pfromthep@ \noexpand\setupDirection@}%
\def\Cshavep@@{\noCshavep@@}\def\Cshavec@@{\noCshavec@@}%
\def\Cslidep@@{\noCslidep@@}\def\Cslidec@@{\noCslidec@@}%
\def\Calong@@{\noCalong@@}%
\ifHidden@\else
\ifdim\Yc>\Ymax \Ymax=\Yc \fi \ifdim\Yp>\Ymax \Ymax=\Yp \fi
\ifdim\Yc<\Ymin \Ymin=\Yc \fi \ifdim\Yp<\Ymin \Ymin=\Yp \fi
\ifdim\Xc>\Xmax \Xmax=\Xc \fi \ifdim\Xp>\Xmax \Xmax=\Xp \fi
\ifdim\Xc<\Xmin \Xmin=\Xc \fi \ifdim\Xp<\Xmin \Xmin=\Xp \fi \fi}
\xydef@\noCshavep@@{\setupDirection@
\enter@{\cfromthec@ \DirectionfromtheDirection@}%
\reverseDirection@ \cfromp@ \the\Edgec\z@
\pfromc@ \leave@ \resetDirection@}
\xydef@\noCshavec@@{\setupDirection@ \the\Edgec\z@ \resetDirection@}
\xydef@\noCslidep@@#1{\dimen@=#1\relax
\advance\Xp\cosDirection\dimen@ \advance\Yp\sinDirection\dimen@
\resetDirection@}
\xydef@\noCslidec@@#1{\dimen@=#1\relax
\advance\Xc\cosDirection\dimen@ \advance\Yc\sinDirection\dimen@
\resetDirection@}
\xydef@\noCalong@@#1{%
\dX=#1\dX \dY=#1\dY \Xc=\Xp \Yc=\Yp \advance\Xc\dX \advance\Yc\dY
\resetupDirection@}
% \straight@{SPREAD}
% Build straight connection...using SPREAD to spread the fillers.
% SPREAD: macro to expand *after* number of fillers N[\count@@] is
% known; has A=w and B=d+h but *before* any filling is done.
% May change N as well as dX,dY,X,Y,w,d,h in order to affect the
% filling.
% Procedure:
% %1 setup Direction parameters now and define the Creset macros
% to reestablish the initial state;
% %2 build macro to discover if the edges of the objects overlap (it
% just verifies that the signs of dX,dY did not change when the
% edges were removed);
% %3 move both p,c to the edges of the objects...and define the Cshave*
% macros accordingly;
% %4 choose either to ignore the connection if requested or there is
% overlap between the objects of choose either vbox or hbox version
% (see below)...
% %5 build Calong@@ macro and reset pc.
% NOTE: Assumes that the Direction is not tampered with between Creset is
% defined and used...
\xydef@\Spread@@{}
\xydef@\checkoverlap@@{}
\xydef@\straight@#1{\setupDirection@ \def\Spread@@{#1}% %1
%
\edef\Creset@@{\cfromthec@ \pfromthep@ \DirectionfromtheDirection@}%
%
\DN@##1##2{\def\checkoverlap@@{% %2
\ifdim##1\Xp>##1\Xc \let\next@=\relax \fi
\ifdim##2\Yp>##2\Yc \let\next@=\relax \fi}}%
\edef\nextii@{{\sdX}{\sdY}}\expandafter\next@\nextii@
%
\noCshavep@@\edef\Cshavep@@{\pfromthep@ \noexpand\resetDirection@}% %3
\noCshavec@@\edef\Cshavec@@{\cfromthec@ \noexpand\resetDirection@}%
%
\ifHidden@\else %3b
\ifdim\Yc>\Ymax \Ymax=\Yc \fi \ifdim\Yp>\Ymax \Ymax=\Yp \fi
\ifdim\Yc<\Ymin \Ymin=\Yc \fi \ifdim\Yp<\Ymin \Ymin=\Yp \fi
\ifdim\Xc>\Xmax \Xmax=\Xc \fi \ifdim\Xp>\Xmax \Xmax=\Xp \fi
\ifdim\Xc<\Xmin \Xmin=\Xc \fi \ifdim\Xp<\Xmin \Xmin=\Xp \fi \fi
%
\ifInvisible@\let\next@=\relax %4
\else\ifdim 1\Direction<-2\K \let\next@=\straightv@
\else\ifdim 1\Direction<\z@ \let\next@=\straighth@
\else\ifdim 1\Direction<2\K \let\next@=\straightv@
\else \let\next@=\straighth@ \fi\fi\fi\fi
\checkoverlap@@ \next@
%
\def\Cslidep@@{\noCslidep@@}\def\Cslidec@@{\noCslidec@@}% %5
\def\Calong@@{\noCalong@@}\Creset@@}
% Now for the works...to summarise: these are parametrised on Direction
% parameters and use
% X,Y: endpoint of connection (`Direction end').
% dX,dY: connection distance (`Direction vector').
% Leftness@: from OBJECT.
% lastobjectbox@: box to fill with; assumed to be `trimmed' to have
% only the size needed for the filler; size is w*(h+d).
% Spread@@: macro to expand to modify the default spreading used.
% Drop@: macro to expand to actually typeset the finished connection
% when it is in box0! NOTE: Must make box0 void to avoid `box
% leaks'.
% Using hbox:
% %0 start box...
% %1 compute initial adjustment (X right and Y up) and...
% A := w, B := h+d, N [\count@@] = floor(|dX| / A),
% and run user supplied Spread;
% %2 adjust first filler position horizontally:
% if dX>0 then X := X-w;
% %4 adjust first filler vertically:
% Y := Y - sdX*L*(dY/dX)*w
% where L = if dX>0 then (1-Leftness) else Leftness;
% %3 recompute the move dimensions (A right and B up):
% A := -sdX(|dX| - w) / (N-1),
% B := sdY|sdX(w)*dY/dX - dY| / (N-1),
% and set the filler box to have w := A;
% %5 output first filler adjusted X,Y and the following N-1 each A
% further right and raised B more than the previous;
% ...and finally end object with usual bravour!
\xydef@\straighth@{\setbox\z@=\hbox{%
%
\A@=\wd\lastobjectbox@ %1
\B@=\dp\lastobjectbox@ \advance\B@\ht\lastobjectbox@
\ifdim \A@=\z@ \count@@=\m@ne
\else \dimen@=\sdX\dX \divide\dimen@\A@ \count@@=\dimen@ \fi
\Spread@@
%
\ifdim\dX>\z@ \advance\Xc-\wd\lastobjectbox@ \fi %2
%
\dimen@=-\sdX\wd\lastobjectbox@ %4
\multiply\dimen@\K@dYdX \divide\dimen@\K
\ifdim\dX>\z@ \advance\Yc\dimen@ \advance\Yc-\Leftness@\dimen@
\else \advance\Yc\Leftness@\dimen@ \fi
%
\dimen@=\wd\lastobjectbox@ \A@=\sdX\dX \advance\A@-\dimen@ %3
\B@=\sdX\dimen@ \multiply\B@\K@dYdX \divide\B@\K \advance\B@-\dY \B@=\sdY\B@
\count@=\count@@ \advance\count@\m@ne
\ifnum\z@<\count@ \divide\A@\count@ \divide\B@\count@ \fi
\A@=-\sdX\A@ \B@=\sdY\B@ \wd\lastobjectbox@=\A@
%
\kern\Xc \count@=\z@ %5
\loop@\ifnum\count@<\count@@ \advance\count@\@ne
\raise\Yc\copy\lastobjectbox@ \advance\Yc\B@ \repeat@}%
%
\ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}}
% Using vtop:
% %0 start box...
% %1 compute initial adjustment (X right and Y up) and...
% A := w, B := h+d, N [\count@@] = floor(|dY| / B),
% and run user supplied Spread;
% %2 adjust vertically for first filler size:
% if dY<0 then Y := Y-h else Y := Y+d;
% %3 recompute the move dimensions (B up and A right):
% B := sdY((|dY| - (h+d)) / (N-1)),
% A := sdX|sdY(h+d)*dX/dY - dX| / (N-1),
% and set the filler box to have h := B, d := 0;
% %4 adjust first filler horizontally:
% X := X + (if dY<0 (1-Upness) else Upness)*A - Leftness*w
% %5 output first filler adjusted X,Y and the following N-1 each -B
% further down and moved A more right than the previous;
% ...and finally end object with usual bravour!
%\xydef@\straightv@{\setbox\z@=\vtop{% %0
%
% \A@=\wd\lastobjectbox@ %1
% \B@=\dp\lastobjectbox@ \advance\B@\ht\lastobjectbox@
% \ifdim \B@=\z@ \count@@=\m@ne
% \else \dimen@=\sdY\dY \divide\dimen@\B@ \count@@=\dimen@ \fi
% \Spread@@
%
% \ifdim\dY<\z@ \advance\Yc-\ht\lastobjectbox@ %2
% \else \advance\Yc\dp\lastobjectbox@ \fi
%
% \dimen@=\dp\lastobjectbox@ \advance\dimen@\ht\lastobjectbox@ %3
% \B@=\sdY\dY \advance\B@-\dimen@
% \A@=\sdY\dimen@ \multiply\A@\K@dXdY \divide\A@\K \advance\A@-\dX
% \A@=\sdX\A@ \count@=\count@@ \advance\count@\m@ne
% \ifnum\z@<\count@ \divide\B@\count@ \divide\A@\count@ \fi
% \B@=\sdY\B@ \A@=\sdX\A@ \ht\lastobjectbox@=\B@ \dp\lastobjectbox@=\z@
%
% \ifdim\dY<\z@ \advance\Xc\A@ \advance\Xc-\Upness@\A@ %4
% \else \advance\Xc\Upness@\A@ \fi
% \advance\Xc-\Leftness@\wd\lastobjectbox@
%
% \null \kern-\Yc \count@=\z@ %5
% \loop@\ifnum\count@<\count@@ \advance\count@\@ne
% \nointerlineskip \moveright\Xc\copy\lastobjectbox@ \advance\Xc\A@ \repeat@}%
% %
% \ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Fix to the |\straightv@| bug.
\DOCMODE(
\xydef@\straightv@{\setbox\z@=\vtop{% %0
%
\A@=\wd\lastobjectbox@ %1
\B@=\dp\lastobjectbox@ \advance\B@\ht\lastobjectbox@
\ifdim \B@=\z@ \count@@=\m@ne
\else \dimen@=\sdY\dY \divide\dimen@\B@ \count@@=\dimen@ \fi
\Spread@@
%
\dimen@=\dp\lastobjectbox@ \advance\dimen@\ht\lastobjectbox@ %3
\B@=\sdY\dY \advance\B@-\dimen@
\A@=\sdY\dimen@ \multiply\A@\K@dXdY \divide\A@\K \advance\A@-\dX
\A@=\sdX\A@ \count@=\count@@ \advance\count@\m@ne
\ifnum\z@<\count@ \divide\B@\count@ \divide\A@\count@ \fi
\B@=\sdY\B@ \A@=\sdX\A@ \ht\lastobjectbox@=\B@ \dp\lastobjectbox@=\z@
%
% \dimen@ still holds the unadjusted \ht+\dp
%
\ifdim\dY<\z@
\advance\Yc\dimen@ \advance\Yc\Upness@\B@
\else
\advance\dimen@\Upness@\B@ \advance\Yc-\dimen@ \advance\Yc\B@
\fi
\advance\Yc\B@
%
\ifdim\dX<\z@ \else \advance\Xc-\wd\lastobjectbox@ \fi
%
\null \kern-\Yc \count@=\z@ %5
\loop@\ifnum\count@<\count@@ \advance\count@\@ne
\nointerlineskip \moveright\Xc\copy\lastobjectbox@ \advance\Xc\A@
\repeat@}%
%
\ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}}
\DOCMODE)
\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section*{End \& log}
\XY-pic ends with a message saying so.
\DOCMODE(
\message{XY-pic loaded}\xyuncatcodes \endinput
\DOCMODE)
\XY-pic is maintained using the RCS ``Revision Control System'' by
Walther F.~Tichy. The following is the revision history since the
first release to Usenet.
\DOCMODE(
% $Log: xy.doc,v $
% Revision 2.12 1994/10/25 11:55:12 kris
% Interim release just before v3 [works with AMS-LaTeX 1.2]...
%
% Revision 2.11 1994/07/05 10:37:32 kris
% Third 3beta release [bug fixes].
% Experimental graph feature included (for ECCT-94 presentation).
%
% Revision 2.10 1994/06/15 12:55:07 kris
% Second 3beta release: bug fixes.
%
% Revision 2.9 1994/06/09 14:59:19 kris
% Release 3beta.
%
% Revision 2.8 1994/04/11 09:31:09 kris
% Second (bug fix) 3alpha release [corrected].
%
% Revision 2.7 1994/03/08 02:06:01 kris
% Release 3alpha.
%
% Revision 2.6.9.1 1994/03/07 04:22:46 kris
% Last internal 3alpha and pre-2.7 release.
%
% MAJOR REWRITE and REORGANISATION:
% File xypic.doc split into separate files: xy.doc for `kernel' and other
% files with the `extensions' and `features'.
% Documented in special DOCMODE LaTeX-based format supported by xydoc.sty.
%
% Revision 2.6.1.1 1992/07/01 07:08:24 kris
% Send to EuroTeX '92...
%
% Revision 2.6 1992/06/24 01:23:34 kris
% Added hooks using font xyqc10.
% Added new POSitions: * and !.
% Added triple lines \Ssolid and \Ddashed.
%
% Revision 2.5 1992/02/24 03:30:54 kris
% Fixed bugs in \Direction calculation logic...
% Added (FACTOR) to \rotate to allow arbitrary rotation.
% ` intermediate points now accept an optional /RADIUS argument.
% Added \Tip with wide tip.
% [See ChangeLog for further details].
%
% Revision 2.4 1992/01/22 02:15:10 kris
% Fixed bugs [with thanks]:
% No spurious arrow heads with LaTeX: \pit now undefined [Werner Struckmann]
% \Solid works: sets \Density [Dave Bowen]
% Short diagonal lines work...major rewrite of \connectv@ [Eric Domenjoud]
%
% Revision 2.3 1992/01/13 23:28:12 kris
% Swapped definitions of \ddtoX and \uutoX [found by Nico Verwer].
% Diagonal lines were wrong [Eric Domenjoud].
%
% Revision 2.2 1992/01/09 04:05:40 kris
% Still problems with rules in frames and horizontal/vertical \solids. Grrr.
%
% Revision 2.1 1992/01/02 14:54:07 kris
% Release version.
%
% Revision 1.40 1991/12/17 04:53:23 kris
% Version distributed as `final draft' on Usenet.
\DOCMODE)
\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tell Emacs that this is a LaTeX document and how it is formatted:
% Local Variables:
% mode:latex
% fill-prefix:"\t"
% fill-column:77
% paragraph-separate:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]"
% paragraph-start:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]"
% TeX-parse-self:nil
% End: